[{"content":"\nA secret message inside a 10,000 hyperdimensional vector\nWe\u0026rsquo;ve seen in previous posts how we can encode data structures using Vector Symbolic Architectures in Clojure. This is an exploration of how we can use this to develop a cipher to transmit a secret message between two parties.\nA Hyperdimensional Cipher Usually, we would develop a dictionary/ cleanup memory of randomly chosen hyperdimensional vectors to represent each symbol. We could do this, but then sharing the dictionary as our key to be able to decode messages would be big. Instead, we could share a single hyperdimensional vector and then use the protect/ rotation operator to create a dictionary of the alphabet and some numbers to order the letters. Think of this as the initial seed symbol and the rest being defined as n+1.\n(def alphabet [:a :b :c :d :e :f :g :h :i :j :k :l :m :n :o :p :q :r :s :t :u :v :w :x :y :z :end-of-message]) (def max-num 4) (def numbers (range 1 (inc max-num))) (def key-codes (into alphabet numbers)) (defn add-keys-to-cleanup-mem! \u0026#34;Take a single hdv as a seed and create an alphabet + numbers of them by using rotation/ protect\u0026#34; [seed-hdv] (vb/reset-hdv-mem!) (doall (reduce (fn [v k] (let [nv (vb/protect v)] (vb/add-hdv! k nv) nv)) seed-hdv key-codes))) We can then encode a message by using a VSA data structure map with the form:\n{1 :c, 2 :a, 3 :t, 4 :s} where the numbers are the key to the order of the sequence of the message.\n(defn encode-message \u0026#34;Encode a message using key value pairs with numbers for ordering\u0026#34; [message] (when (\u0026gt; (count message) max-num) (throw (ex-info \u0026#34;message too long\u0026#34; {:allowed-n max-num}))) (let [ds (zipmap numbers (conj (-\u0026gt;\u0026gt; (mapv str message) (mapv keyword)) :end-of-message))] (println \u0026#34;Encoding \u0026#34; message \u0026#34; into \u0026#34; ds) (vd/clj-\u0026gt;vsa ds))) The message is now in a single hyperdimensional vector. We can decode the message by inspecting each of the numbers in the key value pairs encoded in the data structure.\n(defn decode-message \u0026#34;Decode a message by getting the value of the numbered pairs\u0026#34; [msg] (let [message-v _ (println \u0026#34;decoded message-v \u0026#34; message-v) decoded (-\u0026gt;\u0026gt; message-v (partition-by #(= % :end-of-message)) first (mapv #(if (keyword? %) (name %) (str %))) (apply str))] (println \u0026#34;Decoded message is \u0026#34; decoded) decoded)) Some example code of generating and decoding the message:\n(vb/set-size! 1e4) (def seed-key-hdv (vb/hdv)) (add-keys-to-cleanup-mem! seed-key-hdv) (image/write-image-hdv \u0026#34;seed-key-hdv\u0026#34; seed-key-hdv) (def message (encode-message \u0026#34;cats\u0026#34;)) (image/write-image-hdv \u0026#34;secret-message\u0026#34; message) (decode-message message) ;=\u0026gt; \u0026#34;cats\u0026#34; The cool thing is that both hyperdimensional dictionary and the hyperdimensional encoded message can both be shared as a simple image like these:\nThe seed key to generate the dictionary/ cleanup-mem\nThe encoded secret message\nThen you can load up the seed key/ message from the image. Once you have the dictionary shared, you can create multiple encoded messages with it.\n(def loaded-key (image/read-image-to-hdv \u0026#34;examples/seed-key-hdv.png\u0026#34;)) (add-keys-to-cleanup-mem! loaded-key) (def loaded-message (image/read-image-to-hdv \u0026#34;examples/secret-message.png\u0026#34;)) (decode-message loaded-message) Caveats Please keep in mind that this is just an experiment - do not use for anything important. Another interesting factor to keep in mind is that the VSA operations to get the key value are probabilistic so that the correct decoding is not guaranteed. In fact, I set a limit on the 10,000 dimensional vector message to be 4 letters, which I found to be pretty reliable. For example, with 10,000 dimensions, encoding catsz decoded as katsz.\nIncreasing the number of dimensions lets you encode longer messages. This article is a good companion to look at capacity across different implementations of VSAs.\nConclusion VSAs could be an interesting way to do ciphers. Some advantages could be that the distribution of the information across the vector and the nature of the mapped data structure, it is hard to do things like vowel counting to try to decipher messages. Of course you don\u0026rsquo;t need to have letters and numbers be the only symbols used in the dictionary, they could represent other things as well. The simplicity of being able to encode data structures in a form that can easily be expressed as a black and white image, also lends in its flexibility. Another application might be the ability to combine this technique with deep learning to keep information safe during the training process.\nLink to the full github code\n","permalink":"https://gigasquidsoftware.com/blog/2023/07/02/ciphers-with-vector-symbolic-architectures/","summary":"\u003cp\u003e\u003cimg loading=\"lazy\" src=\"https://raw.githubusercontent.com/gigasquid/vsa-clj/main/examples/secret-message.png\"\u003e\u003c/p\u003e\n\u003cp\u003e\u003cem\u003eA secret message inside a 10,000 hyperdimensional vector\u003c/em\u003e\u003c/p\u003e\n\u003cp\u003eWe\u0026rsquo;ve seen in previous posts how we can encode data structures using \u003ca href=\"http://gigasquidsoftware.com/blog/2022/12/31/vector-symbolic-architectures-in-clojure/\"\u003eVector Symbolic Architectures in Clojure\u003c/a\u003e. This is an exploration of how we can use this to develop a cipher to transmit a secret message between two parties.\u003c/p\u003e\n\u003ch3 id=\"a-hyperdimensional-cipher\"\u003eA Hyperdimensional Cipher\u003c/h3\u003e\n\u003cp\u003eUsually, we would develop a dictionary/ cleanup memory of randomly chosen hyperdimensional vectors to represent each symbol. We could do this, but then sharing the dictionary as our key to be able to decode messages would be big. Instead, we could share a single hyperdimensional vector and then use the protect/ rotation operator to create a dictionary of the alphabet and some numbers to order the letters. Think of this as the initial seed symbol and the rest being defined as \u003ccode\u003en+1\u003c/code\u003e.\u003c/p\u003e","title":"Ciphers with Vector Symbolic Architectures"},{"content":"\ngenerated with Stable Diffusion\nBefore diving into the details of what Vector Symbolic Architectures are and what it means to implement Clojure data structures in them, I\u0026rsquo;d like to start with some of my motivation in this space.\nSmall AI for More Personal Enjoyment Over the last few years, I\u0026rsquo;ve spent time learning, exploring, and contributing to open source deep learning. It continues to amaze me with its rapid movement and achievements at scale. However, the scale is really too big and too slow for me to enjoy it anymore.\nBetween work and family, I don\u0026rsquo;t have a lot of free time. When I do get a few precious hours to do some coding just for me, I want it it to be small enough for me to fire up and play with it in a REPL on my local laptop and get a result back in under two minutes.\nI also believe that the current state of AI is not likely to produce any more meaningful revolutionary innovations in the current mainstream deep learning space. This is not to say that there won\u0026rsquo;t be advances. Just as commercial airlines transformed the original first flight, I\u0026rsquo;m sure we are going to continue to see the transformation of society with current big models at scale - I just think the next leap forward is going to come from somewhere else. And that somewhere else is going to be small AI.\nVector Symbolic Architures aka Hyperdimensional Computing Although I\u0026rsquo;m talking about small AI, VSA or Hyperdimensional computing is based on really big vectors - like 1,000,000 dimensions. The beauty and simplicity in it is that everything is a hypervector - symbols, maps, lists. Through the blessing of high dimensionality, any random hypervector is mathematically guaranteed to be orthogonal to any other one. This all enables some cool things:\nRandom hypervectors can be used to represent symbols (like numbers, strings, keywords, etc..) We can use an algebra to operate on hypervectors: bundling and binding operations create new hypervectors that are compositions of each other and can store and retrieve key value pairs. These operations furthermore are fuzzy due to the nature of working with vectors. In the following code examples, I will be using the concrete model of MAP (Multiply, Add, Permute) by R. Gayler. We can represent Clojure data structures such as maps and vectors in them and perform operations such as get with probabilistic outcomes. Everything is a hypervector! I mean you have a keyword that is a symbol that is a hypervector, then you bundle that with other keywords to be a map. The result is a single hypervector. You then create a sequence structure and add some more in. The result is a single hypervector. The simplicity in the algebra and form of the VSA is beautiful - not unlike LISP itself. Actually, P. Kanerva thought that a LISP could be made from it. In my exploration, I only got as far as making some Clojure data structures, but I\u0026rsquo;m sure it\u0026rsquo;s possible. Start with an Intro and a Paper A good place to start with Vector Symbolic Architectures is actually the paper referenced above - An Introduction to Hyperdimensional Computing for Robots. In general, I find the practice of taking a paper and then trying to implement it a great way to learn.\nTo work with VSAs in Clojure, I needed a high performing Clojure library with tensors and data types. I reached for https://github.com/techascent/tech.datatype. It could handle a million dimensions pretty easily on my laptop.\nTo create a new hypervector - simply chose random values between -1 and 1. This gives us a direction in space which is enough.\n;; Uses Gaylor Method for HDV Operations (def size 1e6) ; big enough for the \u0026#34;Blessing of Dimensionality\u0026#34; (defn binary-rand \u0026#34;Choose a random binary magnitude for the vector +1 or -1\u0026#34; [] (if (\u0026gt; (rand) 0.5) -1 1)) (defn hdv \u0026#34;Create a random hyperdimensional vector of default size\u0026#34; [] (dtt/-\u0026gt;tensor (repeatedly size #(binary-rand)) :datatype :int8)) The only main operations to create key value pairs is addition and matrix multiplication.\nAdding two hyperdimensional vectors, (hdvs), together is calling bundling. Note we clip the values to 1 or -1. At high dimensions, only the direction really matters not the magnitude.\n(defn clip \u0026#34;Clips the hyperdimensional vector magnitude to 1 or -1. We can discard these because of the nature of the large vectors that the mangitudes do not matter\u0026#34; [v] (-\u0026gt; v (dtype-fn/min 1) (dtype-fn/max -1))) (defn bundle \u0026#34;Adds two hyperdimensional vectors together into a single bundle\u0026#34; [v1 v2] (-\u0026gt; (bundle-op v1 v2) (clip))) We can assign key values using bind which is matrix multiplication.\n(defn bind \u0026#34;Binds two HDVs using the multiplication operator. This binding is akin to assigning a symbol to a value. \u0026#34; [v1 v2] (dtype-fn/* v1 v2)) One cool thing is that the binding of a key value pair is also the inverse of itself. So to unbind is just to bind again.\nThe final thing we need is a cleanup memory. The purpose of this is to store the hdv somewhere without any noise. As the hdv gets bundled with other operations there is noise associated with it. It helps to use the cleaned up version by comparing the result to the memory version for future operations. For Clojure, this can be a simple atom.\nFollowing along the example in the paper, we reset the cleanup memory and add some symbols.\n(vb/reset-hdv-mem!) (vb/add-hdv! :name) (vb/add-hdv! \u0026#34;Alice\u0026#34;) (vb/add-hdv! :yob) (vb/add-hdv! 1980) (vb/add-hdv! :high-score) (vb/add-hdv! 1000) Next we create the key value map with combinations of bind and bundle.\n(def H (-\u0026gt; (vb/bind (vb/get-hdv :name) (vb/get-hdv \u0026#34;Alice\u0026#34;)) (vb/bundle (vb/bind (vb/get-hdv :yob) (vb/get-hdv 1980))) (vb/bundle (vb/bind (vb/get-hdv :high-score) (vb/get-hdv 1000))))) So H is just one hypervector as a result of this. We can then query it. unbind-get is using the bind operation as inverse. So if we want to query for the :name value, we get the :name hdv from memory and do the bind operation on the H data structure which is the inverse.\n(vb/unbind-get H :name) ;; [\u0026#34;Alice\u0026#34; #tech.v3.tensor\u0026lt;int8\u0026gt;[1000000] ;; [-1 1 1 ... 1 -1 -1]] We can find other values like :high-score.\n(vb/unbind-get H :high-score) ;; [1000 #tech.v3.tensor\u0026lt;int8\u0026gt;[1000000] ;; [-1 -1 1 ... -1 1 1]] Or go the other way and look for Alice.\n(vb/unbind-get H \u0026#34;Alice\u0026#34;) ;; [:name #tech.v3.tensor\u0026lt;int8\u0026gt;[1000000] ;; [-1 1 -1 ... -1 -1 -1]] Now that we have the fundamentals from the paper, we can try to implement some Clojure data structures.\nClojure Data Structures in VSAs First things first, let\u0026rsquo;s clear our cleanup memory.\n(vb/reset-hdv-mem!) Let\u0026rsquo;s start off with a map, (keeping to non-nested versions to keep things simple).\n(def our-first-vsa-map (vd/clj-\u0026gt;vsa {:x 1 :y 2})) The result is a 1,000,000 dimension hypervector - but remember all the parts are also hypervectors as well. Let\u0026rsquo;s take a look at what is in the cleanup memory so far.\n@vb/cleanup-mem ;; {:x #tech.v3.tensor\u0026lt;int8\u0026gt;[1000000][1 -1 1 ... 1 -1 -1], ;; 1 #tech.v3.tensor\u0026lt;int8\u0026gt;[1000000][1 1 -1 ... -1 -1 -1], ;; :y #tech.v3.tensor\u0026lt;int8\u0026gt;[1000000][1 1 -1 ... 1 1 1], ;; 2 #tech.v3.tensor\u0026lt;int8\u0026gt;[1000000][-1 -1 -1 ... -1 -1 1]} We can write a vsa-get function that takes the composite hypervector of the map and get the value from it by finding the closest match with cosine similarity to the cleanup memory.\n(vd/vsa-get our-first-vsa-map :x) ;; =\u0026gt; [1 #tech.v3.tensor\u0026lt;int8\u0026gt;[1000000][1 1 -1 ... -1 -1 -1] In the example above, the symbolic value is the first item in the vector, in this case the number 1, and the actual hypervector is the second value.\nWe can add onto the map with a new key value pair.\n(def our-second-vsa-map (vd/vsa-assoc our-first-vsa-map :z 3)) (vd/vsa-get our-second-vsa-map :z) ;; =\u0026gt; [3 #tech.v3.tensor\u0026lt;int8\u0026gt;[1000000][1 -1 1 ... -1 -1 1]] We can represent Clojure vectors as VSA data structures as well by using the permute (or rotate) and adding them like a stack.\n(def our-first-vsa-vector-of-maps (vd/clj-\u0026gt;vsa [{:x 1} {:x 2 :y 3}])) ;; We can get the value of x in the 2nd map by (vd/vsa-get our-first-vsa-vector-of-maps :x {:idx 1}) ;; [2 #tech.v3.tensor\u0026lt;int8\u0026gt;[1000000][-1 1 1 ... 1 -1 1]] ;; Or the first map (vd/vsa-get our-first-vsa-vector-of-maps :x {:idx 0}) ;; =\u0026gt; [1 #tech.v3.tensor\u0026lt;int8\u0026gt;[1000000][-1 -1 1 ... 1 1 1]] We can also add onto the Clojure vector with a conj.\n(def our-second-vsa-vector-of-maps (vd/vsa-conj our-first-vsa-vector-of-maps (vd/clj-\u0026gt;vsa {:z 5}))) (vd/vsa-get our-second-vsa-vector-of-maps :z {:idx 2}) ;; =\u0026gt; [5 #tech.v3.tensor\u0026lt;int8\u0026gt;[1000000][-1 1 1 ... -1 -1 -1]] What is really cool about this is that we have built in fuzziness or similarity matching. For example, with this map, we have more than one possibility of matching.\n(def vsa-simple-map (vd/clj-\u0026gt;vsa {:x 1 :y 1 :z 3})) We can see all the possible matches and scores\n(vd/vsa-get vsa-simple-map :x {:threshold -1 :verbose? true}) ;; =\u0026gt; [{1 #tech.v3.tensor\u0026lt;int8\u0026gt;[1000000] ;; [1 -1 1 ... -1 -1 -1], :dot 125165.0, :cos-sim 0.1582533568106879} {:x #tech.v3.tensor\u0026lt;int8\u0026gt;[1000000] ;; [1 -1 -1 ... -1 -1 1], :dot 2493.0, :cos-sim 0.0031520442498225933} {:z #tech.v3.tensor\u0026lt;int8\u0026gt;[1000000] ;; [-1 -1 1 ... 1 1 -1], :dot 439.0, :cos-sim 5.550531190020531E-4} {3 #tech.v3.tensor\u0026lt;int8\u0026gt;[1000000] ;; [-1 -1 1 ... -1 -1 1], :dot -443.0, :cos-sim -5.601105506102723E-4} {:y #tech.v3.tensor\u0026lt;int8\u0026gt;[1000000] ;; [-1 -1 1 ... 1 1 1], :dot -751.0, :cos-sim -9.495327844431478E-4}] This opens up the possibility of defining compound symbolic values and doing fuzzy matching. For example with colors.\n(vb/reset-hdv-mem!) (def primary-color-vsa-map (vd/clj-\u0026gt;vsa {:x :red :y :yellow :z :blue})) Let\u0026rsquo;s add a new compound value to the cleanup memory that is green based on yellow and blue.\n(vb/add-hdv! :green (vb/bundle (vb/get-hdv :yellow) (vb/get-hdv :blue))) Now we can query the hdv color map for things that are close to green.\n(vd/vsa-get primary-color-vsa-map :green {:threshold 0.1}) ;; =\u0026gt; [{:z #tech.v3.tensor\u0026lt;int8\u0026gt;[1000000][1 -1 1 ... -1 1 1]} ;; {:y #tech.v3.tensor\u0026lt;int8\u0026gt;[1000000] [-1 1 1 ... 1 1 1]}] We can also define an inspect function for a hdv by comparing the similarity of all the values of the cleanup memory in it.\n(vd/vsa-inspect primary-color-vsa-map) ;; Note that it includes green in it since it is a compound value ;; =\u0026gt; #{:y :yellow :green :z :red :blue :x} (vd/vsa-inspect (vd/clj-\u0026gt;vsa {:x :red})) ;; =\u0026gt; #{:red :x} Finally, we can implement clojure map and filter functions on the vector data structures that can also include fuzziness.\n(def color-vsa-vector-map (vd/clj-\u0026gt;vsa [{:x :yellow} {:x :green} {:z :red}])) (vd/vsa-map #(-\u0026gt;\u0026gt; (vd/vsa-get % :yellow {:threshold 0.01}) (mapv ffirst)) color-vsa-vector-map) ;; =\u0026gt; ([:x] [:x] []) (-\u0026gt;\u0026gt; color-vsa-vector-map (vd/vsa-filter #(vd/vsa-get % :yellow {:threshold 0.01})) count) ;; =\u0026gt; 2 Wrap Up VSAs and hyperdimensional computing seem like a natural fit for LISP and Clojure. I\u0026rsquo;ve only scratched the surface here in how the two can fit together. I hope that more people are inspired to look into it and small AI with big dimensions.\nFull code and examples here https://github.com/gigasquid/vsa-clj.\nSpecial thanks to Ross Gayler in helping me to implement VSAs and understanding their coolness.\n","permalink":"https://gigasquidsoftware.com/blog/2022/12/31/vector-symbolic-architectures-in-clojure/","summary":"\u003cp\u003e\u003cimg loading=\"lazy\" src=\"https://live.staticflickr.com/65535/52596142860_c4cf8642b0_z.jpg\"\u003e\u003c/p\u003e\n\u003cp\u003e\u003cem\u003egenerated with Stable Diffusion\u003c/em\u003e\u003c/p\u003e\n\u003cp\u003eBefore diving into the details of what Vector Symbolic Architectures are and what it means to implement Clojure data structures in them, I\u0026rsquo;d like to start with some of my motivation in this space.\u003c/p\u003e\n\u003ch2 id=\"small-ai-for-more-personal-enjoyment\"\u003eSmall AI for More Personal Enjoyment\u003c/h2\u003e\n\u003cp\u003eOver the last few years, I\u0026rsquo;ve spent time learning, exploring, and contributing to open source deep learning. It continues to amaze me with its rapid movement and achievements at scale. However, the scale is really too big and too slow for me to enjoy it anymore.\u003c/p\u003e","title":"Vector Symbolic Architectures in Clojure"},{"content":"\nWhat if I told you that you could pick up a library model and instantly classify text with arbitrary categories without any training or fine tuning?\nThat is exactly what we are going to do with Hugging Face\u0026rsquo;s zero-shot learning model. We will also be using libpython-clj to do this exploration without leaving the comfort of our trusty Clojure REPL.\nWhat\u0026rsquo;s for breakfast? We\u0026rsquo;ll start off by taking some text from a recipe description and trying to decide if it\u0026rsquo;s for breakfast, lunch or dinner:\n\u0026quot;French Toast with egg and bacon in the center with maple syrup on top. Sprinkle with powdered sugar if desired.\u0026quot;\nNext we will need to install the required python deps:\npip install numpy torch transformers lime\nNow we just need to set up the libpython clojure namespace to load the Hugging Face transformers library.\n(ns gigasquid.zeroshot (:require [libpython-clj2.python :as py :refer [py. py.. py.-]] [libpython-clj2.require :refer [require-python]])) (require-python \u0026#39;[transformers :bind-ns]) Setup is complete. We are now ready to classify with zeroshot.\nClassify with Zero Shot To create the classifier with zero shot, you need only create it with a handy pipeline function.\n(def classifier (py. transformers \u0026#34;pipeline\u0026#34; \u0026#34;zero-shot-classification\u0026#34;)) After that you need just the text you want to classify and category labels you want to use.\n(def text \u0026#34;French Toast with egg and bacon in the center with maple syrup on top. Sprinkle with powdered sugar if desired.\u0026#34;) (def labels [\u0026#34;breakfast\u0026#34; \u0026#34;lunch\u0026#34; \u0026#34;dinner\u0026#34;]) Classification is only a function call away with:\n(classifier text labels) {\u0026#39;labels\u0026#39;: [\u0026#39;breakfast\u0026#39;, \u0026#39;lunch\u0026#39;, \u0026#39;dinner\u0026#39;], \u0026#39;scores\u0026#39;: [0.989736795425415, 0.007010194938629866, 0.003252972150221467]} Breakfast is the winner. Notice that all the probabilities add up to 1. This is because the default mode for classify uses softmax. We can change that so the categories are each considered independently with the :multi-class option.\n(classifier text labels :multi_class true) {\u0026#39;labels\u0026#39;: [\u0026#39;breakfast\u0026#39;, \u0026#39;lunch\u0026#39;, \u0026#39;dinner\u0026#39;], \u0026#39;scores\u0026#39;: [0.9959920048713684, 0.22608685493469238, 0.031050905585289]} This is a really powerful technique for such an easy to use library. However, how can we do anything with it if we don\u0026rsquo;t understand how it is working and get a handle on how to debug it. We need some level of trust in it for utility.\nThis is where LIME enters.\nUsing LIME for Interpretable Models One of the biggest problems holding back applying state of the art machine learning models to real life problems is that of interpretability and trust. The lime technique is a well designed tool to help with this. One of the reasons that I really like it is that it is model agnostic. This means that you can use it with whatever code you want to use with it as long as you adhere to it\u0026rsquo;s api. You need to provide it with the input and a function that will classify and return the probabilities in a numpy array.\nThe creation of the explainer is only a require away:\n(require-python \u0026#39;[lime.lime_text :as lime]) (require-python \u0026#39;numpy) (def explainer (lime/LimeTextExplainer :class_names labels)) We need to create a function that will take in some text and then return the probabilities for the labels. Since the zeroshot classifier will reorder the returning labels/probs by the value, we need to make sure that it will match up by index to the original labels.\n(defn predict-probs [text] (let [result (classifier text labels) result-scores (get result \u0026#34;scores\u0026#34;) result-labels (get result \u0026#34;labels\u0026#34;) result-map (zipmap result-labels result-scores)] (mapv (fn [cn] (get result-map cn)) labels))) (defn predict-texts [texts] (println \u0026#34;lime texts are \u0026#34; texts) (numpy/array (mapv predict-probs texts))) (predict-texts [text]) ;=\u0026gt; [[0.99718672 0.00281324]] Finally we make an explanation for our text here. We are only using 6 features and 100 samples, to keep the cpus down, but in real life you would want to use closer to the default amount of 5000 samples. The samples are how the explainers work, it modifies the text over and over again and sees the difference in classification values. For example, one of the sample texts for our case is ' Toast with bacon in the center with syrup on . with sugar desired.'.\n(def exp-result (py. explainer \u0026#34;explain_instance\u0026#34; text predict-texts :num_features 6 :num_samples 100)) (py. exp-result \u0026#34;save_to_file\u0026#34; \u0026#34;explanation.html\u0026#34;) Now it becomes more clear. The model is using mainly the word toast to classify it as breakfast with supporting words also being french, egg, maple, and syrup. The word the is also in there too which could be an artifact of the low numbers of samples we used or not. But now at least we have the tools to dig in and understand.\nFinal Thoughts Exciting advances are happening in Deep Learning and NLP. To make them truly useful, we will need to continue to consider how to make them interpretable and debuggable.\nAs always, keep your Clojure REPL handy.\n","permalink":"https://gigasquidsoftware.com/blog/2021/03/15/breakfast-with-zero-shot-nlp/","summary":"\u003cp\u003e\u003cimg loading=\"lazy\" src=\"https://i.imgflip.com/51ror1.jpg\"\u003e\u003c/p\u003e\n\u003cp\u003eWhat if I told you that you could pick up a library model and instantly classify text with arbitrary categories without any training or fine tuning?\u003c/p\u003e\n\u003cp\u003eThat is exactly what we are going to do with \u003ca href=\"https://joeddav.github.io/blog/2020/05/29/ZSL.html\"\u003eHugging Face\u0026rsquo;s zero-shot learning model\u003c/a\u003e. We will also be using \u003ca href=\"https://github.com/clj-python/libpython-clj\"\u003elibpython-clj\u003c/a\u003e to do this exploration without leaving the comfort of our trusty Clojure REPL.\u003c/p\u003e\n\u003ch3 id=\"whats-for-breakfast\"\u003eWhat\u0026rsquo;s for breakfast?\u003c/h3\u003e\n\u003cp\u003eWe\u0026rsquo;ll start off by taking some text from a recipe description and trying to decide if it\u0026rsquo;s for breakfast, lunch or dinner:\u003c/p\u003e","title":"Breakfast with Zero-Shot NLP"},{"content":"\nAI Debate 2 from Montreal.AI I had the pleasure of watching the second AI debate from Montreal.AI last night. The first AI debate occurred last year between Yoshua Bengio and Gary Marcus entitled “The Best Way Forward for AI” in which Yoshua argued that Deep Learning could achieve General AI through its own paradigm, while Marcus argued that Deep Learning alone was not sufficient and needed a hybrid approach involving symbolics and inspiration from other disciplines.\nThis interdisciplinary thread of Gary’s linked the two programs. The second AI debate was entitled “Moving AI Forward: An Interdisciplinary Approach” and reflected a broad panel that explored themes on architecture, neuroscience and psychology, and trust/ethics. The second program was not really a debate, but more of a showcase of ideas in the form of 3 minute presentations from the panelists and discussion around topics with Marcus serving as a capable moderator.\nThe program aired Wednesday night and was 3 hours long. I watched it live with an unavoidable break in the middle to fetch dinner for my family, but the whole recording is up now on the website. Some of the highlights for me were thoughts around System 1 and System 2, reinforcement learning, and the properties of evolution.\nThere was much discussion around System 1 and System 2 in relation to AI. One of the author’s of the recently published paper “Thinking Fast and Slow in AI”, Francesca Rossi was a panelist as well as Danny Kahneman the author of “Thinking Fast and Slow”. Applying the abstraction of these sysems to AI with Deep Learning being System 1 is very appealing, however as Kahneman pointed out in his talk, this abstraction is leaky at its heart as the human System 1 encompasses much more than current AI system 1, (like a model of the world). It is interesting to think of one of the differences in human System 1 and System 2 in relation to one being fast and concurrent while the other is slower and sequential and laden with attention. Why is this so? Is this a constraint and design feature that we should bring to our AI design?\nRichard Sutton gave a thought provoking talk on how reinforcement learning is the first fully implemented computational theory of intelligence. He pointed to Marr’s three levels at which any information processing machine must be understood: hardware implementation, representation/algorithm, and finally the high level theory. That is: what is the goal of the computation? What logic can the strategy be carried out? AI has made great strides due to this computational theory. However, it is only one theory. We need more. I personally think that innovation and exploration in this area could lead to an exciting future in AI.\nEvolution is a fundamental force that drives humans and the world around us. Ken Stanely reminded us that while computers dominate at solving problems, humans still rule at open-ended innovation over the millenia. The underlying properties of evolution still elude our deep understanding. Studying the core nature of this powerful phenomena is a very important area of research.\nThe last question of the evening to all the panelists was the greatest Christmas gift of all - “Where do you want AI to go?”. The diversity of the answers reflected the broad hopes shared by many that will light the way to come. I’ll paraphrase some of the ones here:\nWant to understand fundamental laws and principles and use them to better the human condition. Understand the different varieties of intelligence. Want an intelligent and superfriendly apprentice. To understand self by emulating. To move beyond GPT-3 remixing to really assisting creativity for humanity. Hope that AI will amplify us and our abilities. Use AI to help people understand what bias they have. That humans will still have something to add after AI have mastered a domain To understand the brain in the most simple and beautiful way. Gain a better clarity and understanding of our own values by deciding which to endow our AI with. Want the costs and benefits of AI to be distributed globally and economically. Thanks again Montreal.AI for putting together such a great program and sharing it with the community. I look forward to next year.\nMerry Christmas everyone!\n","permalink":"https://gigasquidsoftware.com/blog/2020/12/24/thoughts-on-ai-debate-2/","summary":"\u003cp\u003e\u003cimg loading=\"lazy\" src=\"https://montrealartificialintelligence.com/aidebate2mosaic1440x720v8.jpg\"\u003e\u003c/p\u003e\n\u003ch2 id=\"ai-debate-2-from-montrealai\"\u003eAI Debate 2 from Montreal.AI\u003c/h2\u003e\n\u003cp\u003eI had the pleasure of watching the second AI debate from Montreal.AI last night. The first AI debate occurred last year between \u003ca href=\"https://yoshuabengio.org/\"\u003eYoshua Bengio\u003c/a\u003e and \u003ca href=\"https://en.wikipedia.org/wiki/Gary_Marcus\"\u003eGary Marcus\u003c/a\u003e entitled \u003ca href=\"https://montrealartificialintelligence.com/aidebate.html\"\u003e“The Best Way Forward for AI”\u003c/a\u003e in which Yoshua argued that Deep Learning could achieve General AI through its own paradigm, while Marcus argued that Deep Learning alone was not sufficient and needed a hybrid approach involving symbolics and inspiration from other disciplines.\u003c/p\u003e","title":"Thoughts on AI Debate 2"},{"content":"\nIn this edition of the blog series of Clojure/Python interop with libpython-clj, we\u0026rsquo;ll be taking a look at two popular Python NLP libraries: NLTK and SpaCy.\nNLTK - Natural Language Toolkit I was taking requests for doing examples of python-clojure interop libraries on twitter the other day, and by far NLTK was the most requested library. After looking into it, I can see why. It\u0026rsquo;s the most popular natural language processing library in Python and you will see it everywhere there is text someone is touching.\nInstallation To use the NLTK toolkit you will need to install it. I use sudo pip3 install nltk, but libpython-clj now supports virtual environments with this PR, so feel free to use whatever is best for you.\nFeatures We\u0026rsquo;ll take a quick tour of the features of NLTK following along initially with the nltk official book and then moving onto this more data task centered tutorial.\nFirst, we need to require all of our things as usual:\n(ns gigasquid.nltk (:require [libpython-clj.require :refer [require-python]] [libpython-clj.python :as py :refer [py. py.. py.-]])) (require-python \u0026#39;([nltk :as nltk])) Downloading packages There are all sorts of packages available to download from NLTK. To start out and tour the library, I would go with a small one that has basic data for the nltk book tutorial.\n(nltk/download \u0026#34;book\u0026#34;) (require-python \u0026#39;([nltk.book :as book])) There are all other sorts of downloads as well, such as (nltk/download \u0026quot;popular\u0026quot;) for most used ones. You can also download \u0026quot;all\u0026quot;, but beware that it is big.\nYou can check out some of the texts it downloaded with:\n(book/texts) ;;; prints out in repl ;; text1: Moby Dick by Herman Melville 1851 ;; text2: Sense and Sensibility by Jane Austen 1811 ;; text3: The Book of Genesis ;; text4: Inaugural Address Corpus ;; text5: Chat Corpus ;; text6: Monty Python and the Holy Grail ;; text7: Wall Street Journal ;; text8: Personals Corpus ;; text9: The Man Who Was Thursday by G . K . Chesterton 1908 book/text1 ;=\u0026gt; \u0026lt;Text: Moby Dick by Herman Melville 1851\u0026gt; book/text2 ;=\u0026gt; \u0026lt;Text: Sense and Sensibility by Jane Austen 1811\u0026gt; You can do fun things like see how many tokens are in a text\n(count (py.- book/text3 tokens)) ;=\u0026gt; 44764 Or even see the lexical diversity, which is a measure of the richness of the text by looking at the unique set of word tokens against the total tokens.\n(defn lexical-diversity [text] (let [tokens (py.- text tokens)] (/ (-\u0026gt; tokens set count) (* 1.0 (count tokens))))) (lexical-diversity book/text3) ;=\u0026gt; 0.06230453042623537 (lexical-diversity book/text5) ;=\u0026gt; 0.13477005109975562 This of course is all very interesting but I prefer to look at some more practical tasks, so we are going to look at some sentence tokenization.\nSentence Tokenization Text can be broken up into individual word tokens or sentence tokens. Let\u0026rsquo;s start off first with the token package\n(require-python \u0026#39;([nltk.tokenize :as tokenize])) (def text \u0026#34;Hello Mr. Smith, how are you doing today? The weather is great, and city is awesome. The sky is pinkish-blue. You shouldn\u0026#39;t eat cardboard\u0026#34;) To tokenize sentences, you take the text and use tokenize/sent_tokenize.\n(def text \u0026#34;Hello Mr. Smith, how are you doing today? The weather is great, and city is awesome. The sky is pinkish-blue. You shouldn\u0026#39;t eat cardboard\u0026#34;) (def tokenized-sent (tokenize/sent_tokenize text)) tokenized-sent ;;=\u0026gt; [\u0026#39;Hello Mr. Smith, how are you doing today?\u0026#39;, \u0026#39;The weather is great, and city is awesome.\u0026#39;, \u0026#39;The sky is pinkish-blue.\u0026#39;, \u0026#34;You shouldn\u0026#39;t eat cardboard\u0026#34;] Likewise, to tokenize words, you use tokenize/word_tokenize:\n(def text \u0026#34;Hello Mr. Smith, how are you doing today? The weather is great, and city is awesome. The sky is pinkish-blue. You shouldn\u0026#39;t eat cardboard\u0026#34;) (def tokenized-sent (tokenize/sent_tokenize text)) tokenized-sent ;;=\u0026gt; [\u0026#39;Hello Mr. Smith, how are you doing today?\u0026#39;, \u0026#39;The weather is great, and city is awesome.\u0026#39;, \u0026#39;The sky is pinkish-blue.\u0026#39;, \u0026#34;You shouldn\u0026#39;t eat cardboard\u0026#34;] (def tokenized-word (tokenize/word_tokenize text)) tokenized-word ;;=\u0026gt; [\u0026#39;Hello\u0026#39;, \u0026#39;Mr.\u0026#39;, \u0026#39;Smith\u0026#39;, \u0026#39;,\u0026#39;, \u0026#39;how\u0026#39;, \u0026#39;are\u0026#39;, \u0026#39;you\u0026#39;, \u0026#39;doing\u0026#39;, \u0026#39;today\u0026#39;, \u0026#39;?\u0026#39;, \u0026#39;The\u0026#39;, \u0026#39;weather\u0026#39;, \u0026#39;is\u0026#39;, \u0026#39;great\u0026#39;, \u0026#39;,\u0026#39;, \u0026#39;and\u0026#39;, \u0026#39;city\u0026#39;, \u0026#39;is\u0026#39;, \u0026#39;awesome\u0026#39;, \u0026#39;.\u0026#39;, \u0026#39;The\u0026#39;, \u0026#39;sky\u0026#39;, \u0026#39;is\u0026#39;, \u0026#39;pinkish-blue\u0026#39;, \u0026#39;.\u0026#39;, \u0026#39;You\u0026#39;, \u0026#39;should\u0026#39;, \u0026#34;n\u0026#39;t\u0026#34;, \u0026#39;eat\u0026#39;, \u0026#39;cardboard\u0026#39;] Frequency Distribution You can also look at the frequency distribution of the words with using the probability package.\n(require-python \u0026#39;([nltk.probability :as probability])) (def fdist (probability/FreqDist tokenized-word)) fdist ;=\u0026gt; \u0026lt;FreqDist with 25 samples and 30 outcomes\u0026gt; (py. fdist most_common) ;=\u0026gt; [(\u0026#39;is\u0026#39;, 3), (\u0026#39;,\u0026#39;, 2), (\u0026#39;The\u0026#39;, 2), (\u0026#39;.\u0026#39;, 2), (\u0026#39;Hello\u0026#39;, 1), (\u0026#39;Mr.\u0026#39;, 1), (\u0026#39;Smith\u0026#39;, 1), (\u0026#39;how\u0026#39;, 1), (\u0026#39;are\u0026#39;, 1), (\u0026#39;you\u0026#39;, 1), (\u0026#39;doing\u0026#39;, 1), (\u0026#39;today\u0026#39;, 1), (\u0026#39;?\u0026#39;, 1), (\u0026#39;weather\u0026#39;, 1), (\u0026#39;great\u0026#39;, 1), (\u0026#39;and\u0026#39;, 1), (\u0026#39;city\u0026#39;, 1), (\u0026#39;awesome\u0026#39;, 1), (\u0026#39;sky\u0026#39;, 1), (\u0026#39;pinkish-blue\u0026#39;, 1), (\u0026#39;You\u0026#39;, 1), (\u0026#39;should\u0026#39;, 1), (\u0026#34;n\u0026#39;t\u0026#34;, 1), (\u0026#39;eat\u0026#39;, 1), (\u0026#39;cardboard\u0026#39;, 1)] Stop Words Stop words are considered noise in text and there are ways to use the library to remove them using the nltk.corpus.\n(def stop-words (into #{} (py. corpus/stopwords words \u0026#34;english\u0026#34;))) stop-words ;=\u0026gt; #{\u0026#34;d\u0026#34; \u0026#34;itself\u0026#34; \u0026#34;more\u0026#34; \u0026#34;didn\u0026#39;t\u0026#34; \u0026#34;ain\u0026#34; \u0026#34;won\u0026#34; \u0026#34;hers\u0026#34;....} Now that we have a collection of the stop words, we can filter them out of our text in the normal way in Clojure.\n(def filtered-sent (-\u0026gt;\u0026gt; tokenized-sent (map tokenize/word_tokenize) (map #(remove stop-words %)))) filtered-sent ;; ((\u0026#34;Hello\u0026#34; \u0026#34;Mr.\u0026#34; \u0026#34;Smith\u0026#34; \u0026#34;,\u0026#34; \u0026#34;today\u0026#34; \u0026#34;?\u0026#34;) ;; (\u0026#34;The\u0026#34; \u0026#34;weather\u0026#34; \u0026#34;great\u0026#34; \u0026#34;,\u0026#34; \u0026#34;city\u0026#34; \u0026#34;awesome\u0026#34; \u0026#34;.\u0026#34;) ;; (\u0026#34;The\u0026#34; \u0026#34;sky\u0026#34; \u0026#34;pinkish-blue\u0026#34; \u0026#34;.\u0026#34;) ;; (\u0026#34;You\u0026#34; \u0026#34;n\u0026#39;t\u0026#34; \u0026#34;eat\u0026#34; \u0026#34;cardboard\u0026#34;)) Lexion Normalization and Lemmatization Stemming and Lemmatization allow ways for the text to be reduced to base words and normalized. For example, the word flying has a stemmed word of fli and a lemma of fly.\n(require-python \u0026#39;([nltk.stem :as stem])) (require-python \u0026#39;([nltk.stem.wordnet :as wordnet])) (let [lem (wordnet/WordNetLemmatizer) stem (stem/PorterStemmer) word \u0026#34;flying\u0026#34;] {:lemmatized-word (py. lem lemmatize word \u0026#34;v\u0026#34;) :stemmed-word (py. stem stem word)}) ;=\u0026gt; {:lemmatized-word \u0026#34;fly\u0026#34;, :stemmed-word \u0026#34;fli\u0026#34;} POS Tagging It also has support for Part-of-Speech (POS) Tagging. A quick example of that is:\n(let [sent \u0026#34;Albert Einstein was born in Ulm, Germany in 1879.\u0026#34; tokens (nltk/word_tokenize sent)] {:tokens tokens :pos-tag (nltk/pos_tag tokens)}) ;; {:tokens ;; [\u0026#39;Albert\u0026#39;, \u0026#39;Einstein\u0026#39;, \u0026#39;was\u0026#39;, \u0026#39;born\u0026#39;, \u0026#39;in\u0026#39;, \u0026#39;Ulm\u0026#39;, \u0026#39;,\u0026#39;, \u0026#39;Germany\u0026#39;, \u0026#39;in\u0026#39;, \u0026#39;1879\u0026#39;, \u0026#39;.\u0026#39;], ;; :pos-tag ;; [(\u0026#39;Albert\u0026#39;, \u0026#39;NNP\u0026#39;), (\u0026#39;Einstein\u0026#39;, \u0026#39;NNP\u0026#39;), (\u0026#39;was\u0026#39;, \u0026#39;VBD\u0026#39;), (\u0026#39;born\u0026#39;, \u0026#39;VBN\u0026#39;), (\u0026#39;in\u0026#39;, \u0026#39;IN\u0026#39;), (\u0026#39;Ulm\u0026#39;, \u0026#39;NNP\u0026#39;), (\u0026#39;,\u0026#39;, \u0026#39;,\u0026#39;), (\u0026#39;Germany\u0026#39;, \u0026#39;NNP\u0026#39;), (\u0026#39;in\u0026#39;, \u0026#39;IN\u0026#39;), (\u0026#39;1879\u0026#39;, \u0026#39;CD\u0026#39;), (\u0026#39;.\u0026#39;, \u0026#39;.\u0026#39;)]} Phew! That\u0026rsquo;s a brief overview of what NLTK can do, now what about the other library SpaCy?\nSpaCy SpaCy is the main competitor to NLTK. It has a more opinionated library which is more object oriented than NLTK which mainly processes text. It has better performance for tokenization and POS tagging and has support for word vectors, which NLTK does not.\nLet\u0026rsquo;s dive in a take a look at it.\nInstallation To install spaCy, you will need to do:\npip3 install spacy python3 -m spacy download en_core_web_sm to load up the small language model We\u0026rsquo;ll be following along this tutorial\nWe will, of course, need to load up the library\n(require-python \u0026#39;([spacy :as spacy])) and its language model:\n(def nlp (spacy/load \u0026#34;en_core_web_sm\u0026#34;)) Linguistic Annotations There are many linguistic annotations that are available, from POS, lemmas, and more:\n(let [doc (nlp \u0026#34;Apple is looking at buying U.K. startup for $1 billion\u0026#34;)] (map (fn [token] [(py.- token text) (py.- token pos_) (py.- token dep_)]) doc)) ;; ([\u0026#34;Apple\u0026#34; \u0026#34;PROPN\u0026#34; \u0026#34;nsubj\u0026#34;] ;; [\u0026#34;is\u0026#34; \u0026#34;AUX\u0026#34; \u0026#34;aux\u0026#34;] ;; [\u0026#34;looking\u0026#34; \u0026#34;VERB\u0026#34; \u0026#34;ROOT\u0026#34;] ;; [\u0026#34;at\u0026#34; \u0026#34;ADP\u0026#34; \u0026#34;prep\u0026#34;] ;; [\u0026#34;buying\u0026#34; \u0026#34;VERB\u0026#34; \u0026#34;pcomp\u0026#34;] ;; [\u0026#34;U.K.\u0026#34; \u0026#34;PROPN\u0026#34; \u0026#34;compound\u0026#34;] ;; [\u0026#34;startup\u0026#34; \u0026#34;NOUN\u0026#34; \u0026#34;dobj\u0026#34;] ;; [\u0026#34;for\u0026#34; \u0026#34;ADP\u0026#34; \u0026#34;prep\u0026#34;] ;; [\u0026#34;$\u0026#34; \u0026#34;SYM\u0026#34; \u0026#34;quantmod\u0026#34;] ;; [\u0026#34;1\u0026#34; \u0026#34;NUM\u0026#34; \u0026#34;compound\u0026#34;] ;; [\u0026#34;billion\u0026#34; \u0026#34;NUM\u0026#34; \u0026#34;pobj\u0026#34;]) Here are some more:\n(let [doc (nlp \u0026#34;Apple is looking at buying U.K. startup for $1 billion\u0026#34;)] (map (fn [token] {:text (py.- token text) :lemma (py.- token lemma_) :pos (py.- token pos_) :tag (py.- token tag_) :dep (py.- token dep_) :shape (py.- token shape_) :alpha (py.- token is_alpha) :is_stop (py.- token is_stop)} ) doc)) ;; ({:text \u0026#34;Apple\u0026#34;, ;; :lemma \u0026#34;Apple\u0026#34;, ;; :pos \u0026#34;PROPN\u0026#34;, ;; :tag \u0026#34;NNP\u0026#34;, ;; :dep \u0026#34;nsubj\u0026#34;, ;; :shape \u0026#34;Xxxxx\u0026#34;, ;; :alpha true, ;; :is_stop false} ;; {:text \u0026#34;is\u0026#34;, ;; :lemma \u0026#34;be\u0026#34;, ;; :pos \u0026#34;AUX\u0026#34;, ;; :tag \u0026#34;VBZ\u0026#34;, ;; :dep \u0026#34;aux\u0026#34;, ;; :shape \u0026#34;xx\u0026#34;, ;; :alpha true, ;; :is_stop true} ;; ... Named Entities It also handles named entities in the same fashion.\n(let [doc (nlp \u0026#34;Apple is looking at buying U.K. startup for $1 billion\u0026#34;)] (map (fn [ent] {:text (py.- ent text) :start-char (py.- ent start_char) :end-char (py.- ent end_char) :label (py.- ent label_)} ) (py.- doc ents))) ;; ({:text \u0026#34;Apple\u0026#34;, :start-char 0, :end-char 5, :label \u0026#34;ORG\u0026#34;} ;; {:text \u0026#34;U.K.\u0026#34;, :start-char 27, :end-char 31, :label \u0026#34;GPE\u0026#34;} ;; {:text \u0026#34;$1 billion\u0026#34;, :start-char 44, :end-char 54, :label \u0026#34;MONEY\u0026#34;}) As you can see, it can handle pretty much the same things as NLTK. But let\u0026rsquo;s take a look at what it can do that NLTK and that is with word vectors.\nWord Vectors In order to use word vectors, you will have to load up a medium or large size data model because the small ones don\u0026rsquo;t ship with word vectors. You can do that at the command line with:\npython3 -m spacy download en_core_web_md You will need to restart your repl and then load it with:\n(require-python \u0026#39;([spacy :as spacy])) (def nlp (spacy/load \u0026#34;en_core_web_md\u0026#34;)) Now you can see cool word vector stuff!\n(let [tokens (nlp \u0026#34;dog cat banana afskfsd\u0026#34;)] (map (fn [token] {:text (py.- token text) :has-vector (py.- token has_vector) :vector_norm (py.- token vector_norm) :is_oov (py.- token is_oov)} ) tokens)) ;; ({:text \u0026#34;dog\u0026#34;, ;; :has-vector true, ;; :vector_norm 7.033673286437988, ;; :is_oov false} ;; {:text \u0026#34;cat\u0026#34;, ;; :has-vector true, ;; :vector_norm 6.680818557739258, ;; :is_oov false} ;; {:text \u0026#34;banana\u0026#34;, ;; :has-vector true, ;; :vector_norm 6.700014114379883, ;; :is_oov false} ;; {:text \u0026#34;afskfsd\u0026#34;, :has-vector false, :vector_norm 0.0, :is_oov true}) And find similarity between different words.\n(let [tokens (nlp \u0026#34;dog cat banana\u0026#34;)] (for [token1 tokens token2 tokens] {:token1 (py.- token1 text) :token2 (py.- token2 text) :similarity (py. token1 similarity token2)})) ;; ({:token1 \u0026#34;dog\u0026#34;, :token2 \u0026#34;dog\u0026#34;, :similarity 1.0} ;; {:token1 \u0026#34;dog\u0026#34;, :token2 \u0026#34;cat\u0026#34;, :similarity 0.8016854524612427} ;; {:token1 \u0026#34;dog\u0026#34;, :token2 \u0026#34;banana\u0026#34;, :similarity 0.2432764321565628} ;; {:token1 \u0026#34;cat\u0026#34;, :token2 \u0026#34;dog\u0026#34;, :similarity 0.8016854524612427} ;; {:token1 \u0026#34;cat\u0026#34;, :token2 \u0026#34;cat\u0026#34;, :similarity 1.0} ;; {:token1 \u0026#34;cat\u0026#34;, :token2 \u0026#34;banana\u0026#34;, :similarity 0.28154364228248596} ;; {:token1 \u0026#34;banana\u0026#34;, :token2 \u0026#34;dog\u0026#34;, :similarity 0.2432764321565628} ;; {:token1 \u0026#34;banana\u0026#34;, :token2 \u0026#34;cat\u0026#34;, :similarity 0.28154364228248596} ;; {:token1 \u0026#34;banana\u0026#34;, :token2 \u0026#34;banana\u0026#34;, :similarity 1.0}) Wrap up We\u0026rsquo;ve seen a grand tour of the two most popular natural language python libraries that you can now use through Clojure interop!\nI hope you\u0026rsquo;ve enjoyed it and if you are interested in exploring yourself, the code examples are here\n","permalink":"https://gigasquidsoftware.com/blog/2020/01/24/clojure-interop-with-python-nlp-libraries/","summary":"\u003cp\u003e\u003cimg alt=\"clojure-python\" loading=\"lazy\" src=\"/images/posts/1c0727cd-49435394578_400fdf1c7f_c.jpg\"\u003e\u003c/p\u003e\n\u003cp\u003eIn this edition of the blog series of Clojure/Python interop with \u003ca href=\"https://github.com/cnuernber/libpython-clj\"\u003elibpython-clj\u003c/a\u003e, we\u0026rsquo;ll be taking a look at two popular Python NLP libraries: \u003ca href=\"https://www.nltk.org/\"\u003eNLTK\u003c/a\u003e and \u003ca href=\"https://spacy.io/\"\u003eSpaCy\u003c/a\u003e.\u003c/p\u003e\n\u003ch2 id=\"nltk---natural-language-toolkit\"\u003eNLTK - Natural Language Toolkit\u003c/h2\u003e\n\u003cp\u003eI was taking requests for doing examples of python-clojure interop libraries on twitter the other day, and by \u003cem\u003efar\u003c/em\u003e NLTK was the most requested library. After looking into it, I can see why. It\u0026rsquo;s the most popular natural language processing library in Python and you will see it everywhere there is text someone is touching.\u003c/p\u003e","title":"Clojure Interop with Python NLP Libraries"},{"content":"libpython-clj has opened the door for Clojure to directly interop with Python libraries. That means we can take just about any Python library and directly use it in our Clojure REPL. But what about matplotlib?\nMatplotlib.pyplot is a standard fixture in most tutorials and python data science code. How do we interop with a python graphics library?\nHow do you interop? It turns out that matplotlib has a headless mode where we can export the graphics and then display it using any method that we would normally use to display a .png file. In my case, I made a quick macro for it using the shell open. I\u0026rsquo;m sure that someone out that could improve upon it, (and maybe even make it a cool utility lib), but it suits what I\u0026rsquo;m doing so far:\nns gigasquid.plot (:require [libpython-clj.require :refer [require-python]] [libpython-clj.python :as py :refer [py. py.. py.-]] [clojure.java.shell :as sh]) ;;; This uses the headless version of matplotlib to generate a graph then copy it to the JVM ;; where we can then print it ;;;; have to set the headless mode before requiring pyplot (def mplt (py/import-module \u0026#34;matplotlib\u0026#34;)) (py. mplt \u0026#34;use\u0026#34; \u0026#34;Agg\u0026#34;) (require-python \u0026#39;matplotlib.pyplot) (require-python \u0026#39;matplotlib.backends.backend_agg) (require-python \u0026#39;numpy) (defmacro with-show \u0026#34;Takes forms with mathplotlib.pyplot to then show locally\u0026#34; [\u0026amp; body] `(let [_# (matplotlib.pyplot/clf) fig# (matplotlib.pyplot/figure) agg-canvas# (matplotlib.backends.backend_agg/FigureCanvasAgg fig#)] ~(cons \u0026#39;do body) (py. agg-canvas# \u0026#34;draw\u0026#34;) (matplotlib.pyplot/savefig \u0026#34;temp.png\u0026#34;) (sh/sh \u0026#34;open\u0026#34; \u0026#34;temp.png\u0026#34;))) Parens for Pyplot! Now that we have our wrapper let\u0026rsquo;s take it for a spin. We\u0026rsquo;ll be following along more or less this tutorial for numpy plotting\nFor setup you will need the following installed in your python environment:\nnumpy matplotlib pillow We are also going to use the latest and greatest syntax from libpython-clj so you are going to need to install the snapshot version locally until the next version goes out:\ngit clone git@github.com:cnuernber/libpython-clj.git cd cd libpython-clj lein install After that is all setup we can require the libs we need in clojure.\n(ns gigasquid.numpy-plot (:require [libpython-clj.require :refer [require-python]] [libpython-clj.python :as py :refer [py. py.. py.-]] [gigasquid.plot :as plot])) The plot namespace contains the macro for with-show above. The py. and others is the new and improved syntax for interop.\nSimple Sin and Cos Let\u0026rsquo;s start off with a simple sine and cosine functions. This code will create a x numpy vector of a range from 0 to 3 * pi in 0.1 increments and then create y numpy vector of the sin of that and plot it\n(let [x (numpy/arange 0 (* 3 numpy/pi) 0.1) y (numpy/sin x)] (plot/with-show (matplotlib.pyplot/plot x y))) Beautiful yes!\nLet\u0026rsquo;s get a bit more complicated now and and plot both the sin and cosine as well as add labels, title, and legend.\n(let [x (numpy/arange 0 (* 3 numpy/pi) 0.1) y-sin (numpy/sin x) y-cos (numpy/cos x)] (plot/with-show (matplotlib.pyplot/plot x y-sin) (matplotlib.pyplot/plot x y-cos) (matplotlib.pyplot/xlabel \u0026#34;x axis label\u0026#34;) (matplotlib.pyplot/ylabel \u0026#34;y axis label\u0026#34;) (matplotlib.pyplot/title \u0026#34;Sine and Cosine\u0026#34;) (matplotlib.pyplot/legend [\u0026#34;Sine\u0026#34; \u0026#34;Cosine\u0026#34;]))) We can also add subplots. Subplots are when you divide the plots into different portions. It is a bit stateful and involves making one subplot active and making changes and then making the other subplot active. Again not too hard to do with Clojure.\n(let [x (numpy/arange 0 (* 3 numpy/pi) 0.1) y-sin (numpy/sin x) y-cos (numpy/cos x)] (plot/with-show ;;; set up a subplot gird that has a height of 2 and width of 1 ;; and set the first such subplot as active (matplotlib.pyplot/subplot 2 1 1) (matplotlib.pyplot/plot x y-sin) (matplotlib.pyplot/title \u0026#34;Sine\u0026#34;) ;;; set the second subplot as active and make the second plot (matplotlib.pyplot/subplot 2 1 2) (matplotlib.pyplot/plot x y-cos) (matplotlib.pyplot/title \u0026#34;Cosine\u0026#34;))) Plotting with Images Pyplot also has functions for working directly with images as well. Here we take a picture of my cat and create another version of it that is tinted.\n(let [img (matplotlib.pyplot/imread \u0026#34;resources/cat.jpg\u0026#34;) img-tinted (numpy/multiply img [1 0.95 0.9])] (plot/with-show (matplotlib.pyplot/subplot 1 2 1) (matplotlib.pyplot/imshow img) (matplotlib.pyplot/subplot 1 2 2) (matplotlib.pyplot/imshow (numpy/uint8 img-tinted)))) Pie charts Finally, we can show how to do a pie chart. I asked people in a twitter thread what they wanted an example of in python interop and one of them was a pie chart. This is for you!\nThe original code for this example came from this tutorial.\n(let [labels [\u0026#34;Frogs\u0026#34; \u0026#34;Hogs\u0026#34; \u0026#34;Dogs\u0026#34; \u0026#34;Logs\u0026#34;] sizes [15 30 45 10] explode [0 0.1 0 0] ; only explode the 2nd slice (Hogs) ] (plot/with-show (let [[fig1 ax1] (matplotlib.pyplot/subplots)] (py. ax1 \u0026#34;pie\u0026#34; sizes :explode explode :labels labels :autopct \u0026#34;%1.1f%%\u0026#34; :shadow true :startangle 90) (py. ax1 \u0026#34;axis\u0026#34; \u0026#34;equal\u0026#34;)) ;equal aspec ration ensures that pie is drawn as circle )) Onwards and Upwards! This is just the beginning. In upcoming posts, I will be showcasing examples of interop with different libraries from the python ecosystem. Part of the goal is to get people used to how to use interop but also to raise awareness of the capabilities of the python libraries out there right now since they have been historically out of our ecosystem.\nIf you have any libraries that you would like examples of, I\u0026rsquo;m taking requests. Feel free to leave them in the comments of the blog or in the twitter thread.\nUntil next time, happy interoping!\nPS All the code examples are here https://github.com/gigasquid/libpython-clj-examples\n","permalink":"https://gigasquidsoftware.com/blog/2020/01/18/parens-for-pyplot/","summary":"\u003cp\u003e\u003ca href=\"https://github.com/cnuernber/libpython-clj\"\u003elibpython-clj\u003c/a\u003e has opened the door for Clojure to directly interop with Python libraries. That means we can take just about any Python library and directly use it in our Clojure REPL. But what about \u003ca href=\"https://matplotlib.org/\"\u003ematplotlib\u003c/a\u003e?\u003c/p\u003e\n\u003cp\u003eMatplotlib.pyplot is a standard fixture in most tutorials and python data science code. How do we interop with a python graphics library?\u003c/p\u003e\n\u003ch2 id=\"how-do-you-interop\"\u003eHow do you interop?\u003c/h2\u003e\n\u003cp\u003eIt turns out that matplotlib has a headless mode where we can export the graphics and then display it using any method that we would normally use to display a .png file. In my case, I made a quick macro for it using the shell \u003ccode\u003eopen\u003c/code\u003e. I\u0026rsquo;m sure that someone out that could improve upon it, (and maybe even make it a cool utility lib), but it suits what I\u0026rsquo;m doing so far:\u003c/p\u003e","title":"Parens for Pyplot"},{"content":"\nA new age in Clojure has dawned. We now have interop access to any python library with libpython-clj.\nLet me pause a minute to repeat.\n** You can now interop with ANY python library. **\nI know. It\u0026rsquo;s overwhelming. It took a bit for me to come to grips with it too.\nLet\u0026rsquo;s take an example of something that I\u0026rsquo;ve always wanted to do and have struggled with mightly finding a way to do it in Clojure:\nI want to use the latest cutting edge GPT2 code out there to generate text.\nRight now, that library is Hugging Face Transformers.\nGet ready. We will wrap that sweet hugging face code in Clojure parens!\nThe setup The first thing you will need to do is to have python3 installed and the two libraries that we need:\npytorch - sudo pip3 install torch hugging face transformers - sudo pip3 install transformers Right now, some of you may not want to proceed. You might have had a bad relationship with Python in the past. It\u0026rsquo;s ok, remember that some of us had bad relationships with Java, but still lead a happy and fulfilled life with Clojure and still can enjoy it from interop. The same is true with Python. Keep an open mind.\nThere might be some others that don\u0026rsquo;t want to have anything to do with Python and want to keep your Clojure pure. Well, that is a valid choice. But you are missing out on what the big, vibrant, and chaotic Python Deep Learning ecosystem has to offer.\nFor those of you that are still along for the ride, let\u0026rsquo;s dive in.\nYour deps file should have just a single extra dependency in it:\n:deps {org.clojure/clojure {:mvn/version \u0026#34;1.10.1\u0026#34;} cnuernber/libpython-clj {:mvn/version \u0026#34;1.30\u0026#34;}} Diving Into Interop The first thing that we need to do is require the libpython library.\n(ns gigasquid.gpt2 (:require [libpython-clj.require :refer [require-python]] [libpython-clj.python :as py])) It has a very nice require-python syntax that we will use to load the python libraries so that we can use them in our Clojure code.\n(require-python \u0026#39;(transformers)) (require-python \u0026#39;(torch)) Here we are going to follow along with the OpenAI GPT-2 tutorial and translate it into interop code. The original tutorial is here\nLet\u0026rsquo;s take the python side first:\nimport torch from transformers import GPT2Tokenizer, GPT2LMHeadModel # Load pre-trained model tokenizer (vocabulary) tokenizer = GPT2Tokenizer.from_pretrained(\u0026#39;gpt2\u0026#39;) This is going to translate in our interop code to:\n(def tokenizer (py/$a transformers/GPT2Tokenizer from_pretrained \u0026#34;gpt2\u0026#34;)) The py/$a function is used to call attributes on a Python object. We get the transformers/GPTTokenizer object that we have available to use and call from_pretrained on it with the string argument \u0026quot;gpt2\u0026quot;\nNext in the Python tutorial is:\n# Encode a text inputs text = \u0026#34;Who was Jim Henson ? Jim Henson was a\u0026#34; indexed_tokens = tokenizer.encode(text) # Convert indexed tokens in a PyTorch tensor tokens_tensor = torch.tensor([indexed_tokens]) This is going to translate to Clojure:\n(def text \u0026#34;Who was Jim Henson ? Jim Henson was a\u0026#34;) ;; encode text input (def indexed-tokens (py/$a tokenizer encode text)) indexed-tokens ;=\u0026gt;[8241, 373, 5395, 367, 19069, 5633, 5395, 367, 19069, 373, 257] ;; convert indexed tokens to pytorch tensor (def tokens-tensor (torch/tensor [indexed-tokens])) tokens-tensor ;; ([[ 8241, 373, 5395, 367, 19069, 5633, 5395, 367, 19069, 373, ;; 257]]) Here we are again using py/$a to call the encode method on the text. However, when we are just calling a function, we can do so directly with (torch/tensor [indexed-tokens]). We can even directly use vectors.\nAgain, you are doing this in the REPL, so you have full power for inspection and display of the python objects. It is a great interop experience - (cider even has doc information on the python functions in the minibuffer)!\nThe next part is to load the model itself. This will take a few minutes, since it has to download a big file from s3 and load it up.\nIn Python:\n# Load pre-trained model (weights) model = GPT2LMHeadModel.from_pretrained(\u0026#39;gpt2\u0026#39;) In Clojure:\n;;; Load pre-trained model (weights) ;;; Note: this will take a few minutes to download everything (def model (py/$a transformers/GPT2LMHeadModel from_pretrained \u0026#34;gpt2\u0026#34;)) The next part is to run the model with the tokens and make the predictions.\nHere the code starts to diverge a tiny bit.\nPython:\n# Set the model in evaluation mode to deactivate the DropOut modules # This is IMPORTANT to have reproducible results during evaluation! model.eval() # If you have a GPU, put everything on cuda tokens_tensor = tokens_tensor.to(\u0026#39;cuda\u0026#39;) model.to(\u0026#39;cuda\u0026#39;) # Predict all tokens with torch.no_grad(): outputs = model(tokens_tensor) predictions = outputs[0] # get the predicted next sub-word (in our case, the word \u0026#39;man\u0026#39;) predicted_index = torch.argmax(predictions[0, -1, :]).item() predicted_text = tokenizer.decode(indexed_tokens + [predicted_index]) assert predicted_text == \u0026#39;Who was Jim Henson? Jim Henson was a man\u0026#39; And Clojure\n;;; Set the model in evaluation mode to deactivate the DropOut modules ;;; This is IMPORTANT to have reproducible results during evaluation! (py/$a model eval) ;;; Predict all tokens (def predictions (py/with [r (torch/no_grad)] (first (model tokens-tensor)))) ;;; get the predicted next sub-word\u0026#34; (def predicted-index (let [last-word-predictions (-\u0026gt; predictions first last) arg-max (torch/argmax last-word-predictions)] (py/$a arg-max item))) predicted-index ;=\u0026gt;582 (py/$a tokenizer decode (-\u0026gt; (into [] indexed-tokens) (conj predicted-index))) ;=\u0026gt; \u0026#34;Who was Jim Henson? Jim Henson was a man\u0026#34; The main differences is that we are obviously not using the python array syntax in our code to manipulate the lists. For example, instead of using outputs[0], we are going to use (first outputs). But, other than that, it is a pretty good match, even with the py/with.\nAlso note that we are not making the call to configure it with GPU. This is intentionally left out to keep things simple for people to try it out. Sometimes, GPU configuration can be a bit tricky to set up depending on your system. For this example, you definitely won\u0026rsquo;t need it since it runs fast enough on cpu. If you do want to do something more complicated later, like fine tuning, you will need to invest some time to get it set up.\nDoing Longer Sequences The next example in the tutorial goes on to cover generating longer text.\nPython\ntokenizer = GPT2Tokenizer.from_pretrained(\u0026#34;gpt2\u0026#34;) model = GPT2LMHeadModel.from_pretrained(\u0026#39;gpt2\u0026#39;) generated = tokenizer.encode(\u0026#34;The Manhattan bridge\u0026#34;) context = torch.tensor([generated]) past = None for i in range(100): print(i) output, past = model(context, past=past) token = torch.argmax(output[0, :]) generated += [token.tolist()] context = token.unsqueeze(0) sequence = tokenizer.decode(generated) print(sequence) And Clojure\n(def tokenizer (py/$a transformers/GPT2Tokenizer from_pretrained \u0026#34;gpt2\u0026#34;)) (def model (py/$a transformers/GPT2LMHeadModel from_pretrained \u0026#34;gpt2\u0026#34;)) (def generated (into [] (py/$a tokenizer encode \u0026#34;The Manhattan bridge\u0026#34;))) (def context (torch/tensor [generated])) (defn generate-sequence-step [{:keys [generated-tokens context past]}] (let [[output past] (model context :past past) token (-\u0026gt; (torch/argmax (first output))) new-generated (conj generated-tokens (py/$a token tolist))] {:generated-tokens new-generated :context (py/$a token unsqueeze 0) :past past :token token})) (defn decode-sequence [{:keys [generated-tokens]}] (py/$a tokenizer decode generated-tokens)) (loop [step {:generated-tokens generated :context context :past nil} i 10] (if (pos? i) (recur (generate-sequence-step step) (dec i)) (decode-sequence step))) ;=\u0026gt; \u0026#34;The Manhattan bridge\\n\\nThe Manhattan bridge is a major artery for\u0026#34; The great thing is once we have it embedded in our code, there is no stopping. We can create a nice function:\n(defn generate-text [starting-text num-of-words-to-predict] (let [tokens (into [] (py/$a tokenizer encode starting-text)) context (torch/tensor [tokens]) result (reduce (fn [r i] (println i) (generate-sequence-step r)) {:generated-tokens tokens :context context :past nil} (range num-of-words-to-predict))] (decode-sequence result))) And finally we can generate some fun text!\n(generate-text \u0026#34;Clojure is a dynamic, general purpose programming language, combining the approachability and interactive\u0026#34; 20) ;=\u0026gt; \u0026#34;Clojure is a dynamic, general purpose programming language, combining the approachability and interactive. It is a language that is easy to learn and use, and is easy to use for anyone\u0026#34; Clojure is a dynamic, general purpose programming language, combining the approachability and interactive. It is a language that is easy to learn and use, and is easy to use for anyone\nSo true GPT2! So true!\nWrap-up libpython-clj is a really powerful tool that will allow Clojurists to better explore, leverage, and integrate Python libraries into their code.\nI\u0026rsquo;ve been really impressed with it so far and I encourage you to check it out.\nThere is a repo with the examples out there if you want to check them out. There is also an example of doing MXNet MNIST classification there as well.\n","permalink":"https://gigasquidsoftware.com/blog/2020/01/10/hugging-face-gpt-with-clojure/","summary":"\u003cp\u003e\u003cimg loading=\"lazy\" src=\"https://live.staticflickr.com/65535/49364554561_6e4f4d0a51_w.jpg\"\u003e\u003c/p\u003e\n\u003cp\u003eA new age in Clojure has dawned. We now have interop access to any python library with \u003ca href=\"https://github.com/cnuernber/libpython-clj\"\u003elibpython-clj\u003c/a\u003e.\u003c/p\u003e\n\u003cbr\u003e\n\u003cp\u003eLet me pause a minute to repeat.\u003c/p\u003e\n\u003cbr\u003e\n\u003cp\u003e** You can now interop with ANY python library. **\u003c/p\u003e\n\u003cbr\u003e\n\u003cp\u003eI know. It\u0026rsquo;s overwhelming. It took a bit for me to come to grips with it too.\u003c/p\u003e\n\u003cbr\u003e\n\u003cp\u003eLet\u0026rsquo;s take an example of something that I\u0026rsquo;ve \u003cem\u003ealways\u003c/em\u003e wanted to do and have struggled with mightly finding a way to do it in Clojure:\u003cbr\u003e\nI want to use the latest cutting edge GPT2 code out there to generate text.\u003c/p\u003e","title":"Hugging Face GPT with Clojure"},{"content":"clojure.spec allows you to write specifications for data and use them for validation. It also provides a generative aspect that allows for robust testing as well as an additional way to understand your data through manual inspection. The dual nature of validation and generation is a natural fit for deep learning models that consist of paired discriminator/generator models.\nTLDR: In this post we show that you can leverage the dual nature of clojure.spec\u0026rsquo;s validator/generator to incorporate a deep learning model\u0026rsquo;s classifier/generator.\nA common use of clojure.spec is at the boundaries to validate that incoming data is indeed in the expected form. Again, this is boundary is a fitting place to integrate models for the deep learning paradigm and our traditional software code.\nBefore we get into the deep learning side of things, let\u0026rsquo;s take a quick refresher on how to use clojure.spec.\nquick view of clojure.spec To create a simple spec for keywords that are cat sounds, we can use s/def.\n(s/def ::cat-sounds #{:meow :purr :hiss}) To do the validation, you can use the s/valid? function.\n(s/valid? ::cat-sounds :meow) ;=\u0026gt; true (s/valid? ::cat-sounds :bark) ;=\u0026gt; false For the generation side of things, we can turn the spec into generator and sample it.\n(gen/sample (s/gen ::cat-sounds)) ;=\u0026gt;(:hiss :hiss :hiss :meow :meow :purr :hiss :meow :meow :meow) There is the ability to compose specs by adding them together with s/and.\n(s/def ::even-number (s/and int? even?)) (gen/sample (s/gen ::even-number)) ;=\u0026gt; (0 0 -2 2 0 10 -4 8 6 8) We can also control the generation by creating a custom generator using s/with-gen. In the following the spec is only that the data be a general string, but using the custom generator, we can restrict the output to only be a certain set of example cat names.\n(s/def ::cat-name (s/with-gen string? #(s/gen #{\u0026#34;Suki\u0026#34; \u0026#34;Bill\u0026#34; \u0026#34;Patches\u0026#34; \u0026#34;Sunshine\u0026#34;}))) (s/valid? ::cat-name \u0026#34;Peaches\u0026#34;) ;=\u0026gt; true (gen/sample (s/gen ::cat-name)) ;; (\u0026#34;Patches\u0026#34; \u0026#34;Sunshine\u0026#34; \u0026#34;Sunshine\u0026#34; \u0026#34;Suki\u0026#34; \u0026#34;Suki\u0026#34; \u0026#34;Sunshine\u0026#34; ;; \u0026#34;Suki\u0026#34; \u0026#34;Patches\u0026#34; \u0026#34;Sunshine\u0026#34; \u0026#34;Suki\u0026#34;) For further information on clojure.spec, I whole-heartedly recommend the spec Guide. But, now with a basic overview of spec, we can move on to creating specs for our Deep Learning models.\nCreating specs for Deep Learning Models In previous posts, we covered making simple autoencoders for handwritten digits.\nThen, we made models that would:\nTake an image of a digit and give you back the string value (ex: \u0026ldquo;2\u0026rdquo;) - post Take a string number value and give you back a digit image. - post We will use both of the models to make a spec with a custom generator.\nNote: For the sake of simplicity, some of the supporting code is left out. But if you want to see the whole code, it is on github\nWith the help of the trained discriminator model, we can make a function that takes in an image and returns the number string value.\n(defn discriminate [image] (-\u0026gt; (m/forward discriminator-model {:data [image]}) (m/outputs) (ffirst) (ndarray/argmax-channel) (ndarray/-\u0026gt;vec) (first) (int))) Let\u0026rsquo;s test it out with a test-image:\n(discriminate my-test-image) ;=\u0026gt; 6 Likewise, with the trained generator model, we can make a function that takes a string number and returns the corresponding image.\n(defn generate [label] (-\u0026gt; (m/forward generator-model {:data [(ndarray/array [label] [batch-size])]}) (m/outputs) (ffirst))) Giving it a test drive as well:\n(def generated-test-image (generate 3)) (viz/im-sav {:title \u0026#34;generated-image\u0026#34; :output-path \u0026#34;results/\u0026#34; :x (ndarray/reshape generated-test-image [batch-size 1 28 28])}) Great! Let\u0026rsquo;s go ahead and start writing specs. First let\u0026rsquo;s make a quick spec to describe a MNIST number - which is a single digit between 0 and 9.\n(s/def ::mnist-number (s/and int? #(\u0026lt;= 0 % 9))) (s/valid? ::mnist-number 3) ;=\u0026gt; true (s/valid? ::mnist-number 11) ;=\u0026gt; false (gen/sample (s/gen ::mnist-number)) ;=\u0026gt; (0 1 0 3 5 3 7 5 0 1) We now have both parts to validate and generate and can create a spec for it.\n(s/def ::mnist-image (s/with-gen #(s/valid? ::mnist-number (discriminate %)) #(gen/fmap (fn [n] (do (ndarray/copy (generate n)))) (s/gen ::mnist-number)))) The ::mnist-number spec is used for the validation after the discriminate model is used. On the generator side, we use the generator for the ::mnist-number spec and feed that into the deep learning generator model to get sample images.\nWe have a test function that will help us test out this new spec, called test-model-spec. It will return a map with the following form:\n{:spec name-of-the-spec :valid? whether or not the `s/valid?` called on the test value is true or not :sample-values This calls the discriminator model on the generated values } It will also write an image of all the sample images to a file named sample-spec-name\nLet\u0026rsquo;s try it on our test image:\n(s/valid? ::mnist-image my-test-image) ;=\u0026gt; true (test-model-spec ::mnist-image my-test-image) ;; {:spec \u0026#34;mnist-image\u0026#34; ;; :valid? true ;; :sample-values [0 0 0 1 3 1 0 2 7 3]} Pretty cool!\nLet\u0026rsquo;s do some more specs. But first, our spec is going to be a bit repetitive, so we\u0026rsquo;ll make a quick macro to make things easier.\n(defmacro def-model-spec [spec-key spec discriminate-fn generate-fn] `(s/def ~spec-key (s/with-gen #(s/valid? ~spec (~discriminate-fn %)) #(gen/fmap (fn [n#] (do (ndarray/copy (~generate-fn n#)))) (s/gen ~spec))))) More Specs - More Fun This time let\u0026rsquo;s define an even mnist image spec\n(def-model-spec ::even-mnist-image (s/and ::mnist-number even?) discriminate generate) (test-model-spec ::even-mnist-image my-test-image) ;; {:spec \u0026#34;even-mnist-image\u0026#34; ;; :valid? true ;; :sample-values [0 0 2 0 8 2 2 2 0 0]} And Odds\n(def-model-spec ::odd-mnist-image (s/and ::mnist-number odd?) discriminate generate) (test-model-spec ::odd-mnist-image my-test-image) ;; {:spec \u0026#34;odd-mnist-image\u0026#34; ;; :valid? false ;; :sample-values [5 1 5 1 3 3 3 1 1 1]} Finally, let\u0026rsquo;s do Odds that are over 2!\n(def-model-spec ::odd-over-2-mnist-image (s/and ::mnist-number odd? #(\u0026gt; % 2)) discriminate generate) (test-model-spec ::odd-over-2-mnist-image my-test-image) ;; {:spec \u0026#34;odd-over-2-mnist-image\u0026#34; ;; :valid? false ;; :sample-values [3 3 3 5 3 5 7 7 7 3]} Conclusion We have shown some of the potential of integrating deep learning models with Clojure. clojure.spec is a powerful tool and it can be leveraged in new and interesting ways for both deep learning and AI more generally.\nI hope that more people are intrigued to experiment and take a further look into what we can do in this area.\n","permalink":"https://gigasquidsoftware.com/blog/2019/10/11/integrating-deep-learning-with-clojure.spec/","summary":"\u003cp\u003eclojure.spec allows you to write specifications for data and use them for validation. It also provides a generative aspect that allows for robust testing as well as an additional way to understand your data through manual inspection. The dual nature of validation and generation is a natural fit for deep learning models that consist of paired discriminator/generator models.\u003c/p\u003e\n\u003cbr\u003e\n\u003cp\u003e\u003cstrong\u003e\u003cstrong\u003eTLDR: In this post we show that you can leverage the dual nature of clojure.spec\u0026rsquo;s validator/generator to incorporate a deep learning model\u0026rsquo;s classifier/generator.\u003c/strong\u003e\u003c/strong\u003e\u003c/p\u003e","title":"Integrating Deep Learning with clojure.spec"},{"content":"\nIn this first post of this series, we took a look at a simple autoencoder. It took and image and transformed it back to an image. Then, we focused in on the disciminator portion of the model, where we took an image and transformed it to a label. Now, we focus in on the generator portion of the model do the inverse operation: we transform a label to an image. In recap:\nAutoencoder: image -\u0026gt; image Discriminator: image -\u0026gt; label Generator: label -\u0026gt; image (This is what we are doing now!) Still Need Data of Course Nothing changes here. We are still using the MNIST handwritten digit set and have an input and out to our model.\n(def train-data (mx-io/mnist-iter {:image (str data-dir \u0026#34;train-images-idx3-ubyte\u0026#34;) :label (str data-dir \u0026#34;train-labels-idx1-ubyte\u0026#34;) :input-shape [784] :flat true :batch-size batch-size :shuffle true})) (def test-data (mx-io/mnist-iter {:image (str data-dir \u0026#34;t10k-images-idx3-ubyte\u0026#34;) :label (str data-dir \u0026#34;t10k-labels-idx1-ubyte\u0026#34;) :input-shape [784] :batch-size batch-size :flat true :shuffle true})) (def input (sym/variable \u0026#34;input\u0026#34;)) (def output (sym/variable \u0026#34;input_\u0026#34;)) The Generator Model The model does change to one hot encode the label for the number. Other than that, it\u0026rsquo;s pretty much the exact same second half of the autoencoder model.\n(defn get-symbol [] (as-\u0026gt; input data (sym/one-hot \u0026#34;onehot\u0026#34; {:indices data :depth 10}) ;; decode (sym/fully-connected \u0026#34;decode1\u0026#34; {:data data :num-hidden 50}) (sym/activation \u0026#34;sigmoid3\u0026#34; {:data data :act-type \u0026#34;sigmoid\u0026#34;}) ;; decode (sym/fully-connected \u0026#34;decode2\u0026#34; {:data data :num-hidden 100}) (sym/activation \u0026#34;sigmoid4\u0026#34; {:data data :act-type \u0026#34;sigmoid\u0026#34;}) ;;output (sym/fully-connected \u0026#34;result\u0026#34; {:data data :num-hidden 784}) (sym/activation \u0026#34;sigmoid5\u0026#34; {:data data :act-type \u0026#34;sigmoid\u0026#34;}) (sym/linear-regression-output {:data data :label output}))) (def data-desc (first (mx-io/provide-data-desc train-data))) (def label-desc (first (mx-io/provide-label-desc train-data))) When binding the shapes to the model, we now need to specify that the input data shapes is the label instead of the image and the output of the model is going to be the image.\n(def model ;;; change data shapes to label shapes (-\u0026gt; (m/module (get-symbol) {:data-names [\u0026#34;input\u0026#34;] :label-names [\u0026#34;input_\u0026#34;]}) (m/bind {:data-shapes [(assoc label-desc :name \u0026#34;input\u0026#34;)] :label-shapes [(assoc data-desc :name \u0026#34;input_\u0026#34;)]}) (m/init-params {:initializer (initializer/uniform 1)}) (m/init-optimizer {:optimizer (optimizer/adam {:learning-rage 0.001})}))) (def my-metric (eval-metric/mse)) Training The training of the model is pretty straight forward. Just being mindful that we are using hte batch-label, (number label), as the input and and validating with the batch-data, (image).\n(defn train [num-epochs] (doseq [epoch-num (range 0 num-epochs)] (println \u0026#34;starting epoch \u0026#34; epoch-num) (mx-io/do-batches train-data (fn [batch] ;;; change input to be the label (-\u0026gt; model (m/forward {:data (mx-io/batch-label batch) :label (mx-io/batch-data batch)}) (m/update-metric my-metric (mx-io/batch-data batch)) (m/backward) (m/update)))) (println \u0026#34;result for epoch \u0026#34; epoch-num \u0026#34; is \u0026#34; (eval-metric/get-and-reset my-metric)))) Results Before Training (def my-test-batch (mx-io/next test-data)) ;;; change to input labels (def test-labels (mx-io/batch-label my-test-batch)) (def preds (m/predict-batch model {:data test-labels} )) (viz/im-sav {:title \u0026#34;before-training-preds\u0026#34; :output-path \u0026#34;results/\u0026#34; :x (ndarray/reshape (first preds) [100 1 28 28])}) (-\u0026gt;\u0026gt; test-labels first ndarray/-\u0026gt;vec (take 10)) ;=\u0026gt; (6.0 1.0 0.0 0.0 3.0 1.0 4.0 8.0 0.0 9.0) Not very impressive\u0026hellip; Let\u0026rsquo;s train\n(train 3) starting epoch 0 result for epoch 0 is [mse 0.0723091] starting epoch 1 result for epoch 1 is [mse 0.053891845] starting epoch 2 result for epoch 2 is [mse 0.05337505] Results After Training (def my-test-batch (mx-io/next test-data)) (def test-labels (mx-io/batch-label my-test-batch)) (def preds (m/predict-batch model {:data test-labels})) (viz/im-sav {:title \u0026#34;after-training-preds\u0026#34; :output-path \u0026#34;results/\u0026#34; :x (ndarray/reshape (first preds) [100 1 28 28])}) (-\u0026gt;\u0026gt; test-labels first ndarray/-\u0026gt;vec (take 10)) ;=\u0026gt; (9.0 5.0 7.0 1.0 8.0 6.0 6.0 0.0 8.0 1.0) Cool! The first row is indeed\n(9.0 5.0 7.0 1.0 8.0 6.0 6.0 0.0 8.0 1.0)\nSave Your Model Don\u0026rsquo;t forget to save the generator model off - we are going to use it next time.\n(m/save-checkpoint model {:prefix \u0026#34;model/generator\u0026#34; :epoch 2}) Happy Deep Learning until next time \u0026hellip;\n","permalink":"https://gigasquidsoftware.com/blog/2019/09/06/focus-on-the-generator/","summary":"\u003cp\u003e\u003ca data-flickr-embed=\"true\"  href=\"https://www.flickr.com/photos/smigla-bobinski/19705409981/in/album-72157647756733695/\" title=\"SIMULACRA by Karina Smigla-Bobinski\"\u003e\u003cimg src=\"https://live.staticflickr.com/330/19705409981_4e0ae93572.jpg\" width=\"500\" height=\"267\" alt=\"SIMULACRA by Karina Smigla-Bobinski\"\u003e\u003c/a\u003e\u003cscript async src=\"//embedr.flickr.com/assets/client-code.js\" charset=\"utf-8\"\u003e\u003c/script\u003e\u003c/p\u003e\n\u003cp\u003eIn this first post of this series, we took a look at a \u003ca href=\"https://gigasquidsoftware.com/blog/2019/08/16/simple-autoencoder/\"\u003esimple autoencoder\u003c/a\u003e. It took and image and transformed it back to an image. Then, we \u003ca href=\"https://gigasquidsoftware.com/blog/2019/08/30/focus-on-the-discriminator/\"\u003efocused in on the disciminator\u003c/a\u003e portion of the model, where we took an image and transformed it to a label. Now, we focus in on the generator portion of the model do the inverse operation: we transform a label to an image. In recap:\u003c/p\u003e","title":"Focus On the Generator"},{"content":"\nIn the last post, we took a look at a simple autoencoder. The autoencoder is a deep learning model that takes in an image and, (through an encoder and decoder), works to produce the same image. In short:\nAutoencoder: image -\u0026gt; image For a discriminator, we are going to focus on only the first half on the autoencoder.\nWhy only half? We want a different transformation. We are going to want to take an image as input and then do some discrimination of the image and classify what type of image it is. In our case, the model is going to input an image of a handwritten digit and attempt to decide which number it is.\nDiscriminator: image -\u0026gt; label As always, with deep learning. To do anything, we need data.\nMNIST Data Nothing changes here from the autoencoder code. We are still using the MNIST dataset for handwritten digits.\n;;; Load the MNIST datasets (def train-data (mx-io/mnist-iter {:image (str data-dir \u0026#34;train-images-idx3-ubyte\u0026#34;) :label (str data-dir \u0026#34;train-labels-idx1-ubyte\u0026#34;) :input-shape [784] :flat true :batch-size batch-size :shuffle true})) (def test-data (mx-io/mnist-iter {:image (str data-dir \u0026#34;t10k-images-idx3-ubyte\u0026#34;) :label (str data-dir \u0026#34;t10k-labels-idx1-ubyte\u0026#34;) :input-shape [784] :batch-size batch-size :flat true :shuffle true})) The model will change since we want a different output.\nThe Model We are still taking in the image as input, and using the same encoder layers from the autoencoder model. However, at the end, we use a fully connected layer that has 10 hidden nodes - one for each label of the digits 0-9. Then we use a softmax for the classification output.\n(def input (sym/variable \u0026#34;input\u0026#34;)) (def output (sym/variable \u0026#34;input_\u0026#34;)) (defn get-symbol [] (as-\u0026gt; input data ;; encode (sym/fully-connected \u0026#34;encode1\u0026#34; {:data data :num-hidden 100}) (sym/activation \u0026#34;sigmoid1\u0026#34; {:data data :act-type \u0026#34;sigmoid\u0026#34;}) ;; encode (sym/fully-connected \u0026#34;encode2\u0026#34; {:data data :num-hidden 50}) (sym/activation \u0026#34;sigmoid2\u0026#34; {:data data :act-type \u0026#34;sigmoid\u0026#34;}) ;;; this last bit changed from autoencoder ;;output (sym/fully-connected \u0026#34;result\u0026#34; {:data data :num-hidden 10}) (sym/softmax-output {:data data :label output}))) In the autoencoder, we were never actually using the label, but we will certainly need to use it this time. It is reflected in the model\u0026rsquo;s bindings with the data and label shapes.\n(def model (-\u0026gt; (m/module (get-symbol) {:data-names [\u0026#34;input\u0026#34;] :label-names [\u0026#34;input_\u0026#34;]}) (m/bind {:data-shapes [(assoc data-desc :name \u0026#34;input\u0026#34;)] :label-shapes [(assoc label-desc :name \u0026#34;input_\u0026#34;)]}) (m/init-params {:initializer (initializer/uniform 1)}) (m/init-optimizer {:optimizer (optimizer/adam {:learning-rage 0.001})}))) For the evaluation metric, we are also going to use an accuracy metric vs a mean squared error (mse) metric\n(def my-metric (eval-metric/accuracy)) With these items in place, we are ready to train the model.\nTraining The training from the autoencoder needs to changes to use the real label for the the forward pass and updating the metric.\n(defn train [num-epochs] (doseq [epoch-num (range 0 num-epochs)] (println \u0026#34;starting epoch \u0026#34; epoch-num) (mx-io/do-batches train-data (fn [batch] ;;; here we make sure to use the label ;;; now for forward and update-metric (-\u0026gt; model (m/forward {:data (mx-io/batch-data batch) :label (mx-io/batch-label batch)}) (m/update-metric my-metric (mx-io/batch-label batch)) (m/backward) (m/update)))) (println {:epoch epoch-num :metric (eval-metric/get-and-reset my-metric)}))) Let\u0026rsquo;s Run Things It\u0026rsquo;s always a good idea to take a look at things before you start training.\nThe first batch of the training data looks like:\n(def my-batch (mx-io/next train-data)) (def images (mx-io/batch-data my-batch)) (viz/im-sav {:title \u0026#34;originals\u0026#34; :output-path \u0026#34;results/\u0026#34; :x (-\u0026gt; images first (ndarray/reshape [100 1 28 28]))}) Before training, if we take the first batch from the test data and predict what the labels are:\n(def my-test-batch (mx-io/next test-data)) (def test-images (mx-io/batch-data my-test-batch)) (viz/im-sav {:title \u0026#34;test-images\u0026#34; :output-path \u0026#34;results/\u0026#34; :x (-\u0026gt; test-images first (ndarray/reshape [100 1 28 28]))}) (def preds (m/predict-batch model {:data test-images} )) (-\u0026gt;\u0026gt; preds first (ndarray/argmax-channel) (ndarray/-\u0026gt;vec) (take 10)) ;=\u0026gt; (1.0 8.0 8.0 8.0 8.0 8.0 2.0 8.0 8.0 1.0) Yeah, not even close. The real first line of the images is 6 1 0 0 3 1 4 8 0 9\nLet\u0026rsquo;s Train!\n(train 3) ;; starting epoch 0 ;; {:epoch 0, :metric [accuracy 0.83295]} ;; starting epoch 1 ;; {:epoch 1, :metric [accuracy 0.9371333]} ;; starting epoch 2 ;; {:epoch 2, :metric [accuracy 0.9547667]} After the training, let\u0026rsquo;s have another look at the predicted labels.\n(def preds (m/predict-batch model {:data test-images} )) (-\u0026gt;\u0026gt; preds first (ndarray/argmax-channel) (ndarray/-\u0026gt;vec) (take 10)) ;=\u0026gt; (6.0 1.0 0.0 0.0 3.0 1.0 4.0 8.0 0.0 9.0) Predicted = (6.0 1.0 0.0 0.0 3.0 1.0 4.0 8.0 0.0 9.0) Actual = 6 1 0 0 3 1 4 8 0 9 Rock on!\nClosing In this post, we focused on the first half of the autoencoder and made a discriminator model that took in an image and gave us a label.\nDon\u0026rsquo;t forget to save the trained model for later, we\u0026rsquo;ll be using it.\n(m/save-checkpoint model {:prefix \u0026#34;model/discriminator\u0026#34; :epoch 2}) Until then, here is a picture of the cat in a basket to keep you going.\nP.S. If you want to run all the code for yourself. It is here\n","permalink":"https://gigasquidsoftware.com/blog/2019/08/30/focus-on-the-discriminator/","summary":"\u003cp\u003e\u003ca data-flickr-embed=\"true\"  href=\"https://www.flickr.com/photos/marcomagrini/698692268/in/photolist-24JYSq-hTTAJN-4gjQW9-9GRKCW-4gfNhz-x2yZ-6Nnwy1-6Lm68p-66BVjW-8hawRk-4sE2Jz-5Z6uvQ-6B4iH3-qzDvGU-aNpvLT-9UFZLh-egKvNt-bMh6PR-ceG9AL-gDqtze-96JhRW-7EWMH6-3MTfDt-9rUJ4W-dFPssj-8LLrys-aDAda3-9rUJ45-7xLAFR-prSHik-7yDFHC-7erqEc-6YJx8e-39SyR4-dkQnGi-7hy6zT-4UokrH-hkMoBr-9tBN3K-jq8Bpu-aDMSk2-pwQdmt-9tFrUD-6TzF6G-WDAsCC-8Mm4tD-8M8hyS-4yzkGK-67MPUw-crfg\" title=\"sunflowers\"\u003e\u003cimg src=\"https://live.staticflickr.com/1007/698692268_b31d429272.jpg\" width=\"500\" height=\"325\" alt=\"sunflowers\"\u003e\u003c/a\u003e\u003cscript async src=\"//embedr.flickr.com/assets/client-code.js\" charset=\"utf-8\"\u003e\u003c/script\u003e\u003c/p\u003e\n\u003cp\u003eIn the \u003ca href=\"https://gigasquidsoftware.com/blog/2019/08/16/simple-autoencoder/\"\u003elast post\u003c/a\u003e, we took a look at a simple autoencoder. The autoencoder is a deep learning model that takes in an image and, (through an encoder and decoder), works to produce the same image. In short:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eAutoencoder: image -\u0026gt; image\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eFor a discriminator, we are going to focus on only the first half on the autoencoder.\u003c/p\u003e\n\u003cp\u003e\u003cimg alt=\"discriminator\" loading=\"lazy\" src=\"https://live.staticflickr.com/65535/48647347383_9577b7b672_b.jpg\"\u003e\u003c/p\u003e\n\u003cp\u003eWhy only half? We want a different transformation. We are going to want to take an image as input and then do some \u003cem\u003ediscrimination\u003c/em\u003e of the image and classify what type of image it is. In our case, the model is going to input an image of a handwritten digit and attempt to decide which number it is.\u003c/p\u003e","title":"Focus on the Discriminator"},{"content":"\nIf you look long enough into the autoencoder, it looks back at you.\nThe Autoencoder is a fun deep learning model to look into. Its goal is simple: given an input image, we would like to have the same output image.\nIt\u0026rsquo;s sort of an identity function for deep learning models, but it is composed of two parts: an encoder and decoder, with the encoder translating the images to a latent space representation and the encoder translating that back to a regular images that we can view.\nWe are going to make a simple autoencoder with Clojure MXNet for handwritten digits using the MNIST dataset.\nThe Dataset We first load up the training data into an iterator that will allow us to cycle through all the images.\n(def train-data (mx-io/mnist-iter {:image (str data-dir \u0026#34;train-images-idx3-ubyte\u0026#34;) :label (str data-dir \u0026#34;train-labels-idx1-ubyte\u0026#34;) :input-shape [784] :flat true :batch-size batch-size :shuffle true})) Notice there the the input shape is 784. We are purposely flattening out our 28x28 image of a number to just be a one dimensional flat array. The reason is so that we can use a simpler model for the autoencoder.\nWe also load up the corresponding test data.\n(def test-data (mx-io/mnist-iter {:image (str data-dir \u0026#34;t10k-images-idx3-ubyte\u0026#34;) :label (str data-dir \u0026#34;t10k-labels-idx1-ubyte\u0026#34;) :input-shape [784] :batch-size batch-size :flat true :shuffle true})) When we are working with deep learning models we keep the training and the test data separate. When we train the model, we won\u0026rsquo;t use the test data. That way we can evaluate it later on the unseen test data.\nThe Model Now we need to define the layers of the model. We know we are going to have an input and an output. The input will be the array that represents the image of the digit and the output will also be an array which is reconstruction of that image.\n(def input (sym/variable \u0026#34;input\u0026#34;)) (def output (sym/variable \u0026#34;input_\u0026#34;)) (defn get-symbol [] (as-\u0026gt; input data ;; encode (sym/fully-connected \u0026#34;encode1\u0026#34; {:data data :num-hidden 100}) (sym/activation \u0026#34;sigmoid1\u0026#34; {:data data :act-type \u0026#34;sigmoid\u0026#34;}) ;; encode (sym/fully-connected \u0026#34;encode2\u0026#34; {:data data :num-hidden 50}) (sym/activation \u0026#34;sigmoid2\u0026#34; {:data data :act-type \u0026#34;sigmoid\u0026#34;}) ;; decode (sym/fully-connected \u0026#34;decode1\u0026#34; {:data data :num-hidden 50}) (sym/activation \u0026#34;sigmoid3\u0026#34; {:data data :act-type \u0026#34;sigmoid\u0026#34;}) ;; decode (sym/fully-connected \u0026#34;decode2\u0026#34; {:data data :num-hidden 100}) (sym/activation \u0026#34;sigmoid4\u0026#34; {:data data :act-type \u0026#34;sigmoid\u0026#34;}) ;;output (sym/fully-connected \u0026#34;result\u0026#34; {:data data :num-hidden 784}) (sym/activation \u0026#34;sigmoid5\u0026#34; {:data data :act-type \u0026#34;sigmoid\u0026#34;}) (sym/linear-regression-output {:data data :label output}))) From the model above we can see the input (image) being passed through simple layers of encoder to its latent representation, and then boosted back up from the decoder back into an output (image). It goes through the pleasingly symmetric transformation of:\n784 (image) -\u0026gt; 100 -\u0026gt; 50 -\u0026gt; 50 -\u0026gt; 100 -\u0026gt; 784 (output)\nWe can now construct the full model with the module api from clojure-mxnet.\n(def data-desc (first (mx-io/provide-data-desc train-data))) (def model (-\u0026gt; (m/module (get-symbol) {:data-names [\u0026#34;input\u0026#34;] :label-names [\u0026#34;input_\u0026#34;]}) (m/bind {:data-shapes [(assoc data-desc :name \u0026#34;input\u0026#34;)] :label-shapes [(assoc data-desc :name \u0026#34;input_\u0026#34;)]}) (m/init-params {:initializer (initializer/uniform 1)}) (m/init-optimizer {:optimizer (optimizer/adam {:learning-rage 0.001})}))) Notice that when we are binding the data-shapes and label-shapes we are using only the data from our handwritten digit dataset, (the images), and not the labels. This will ensure that as it trains it will seek to recreate the input image for the output image.\nBefore Training Before we start our training, let\u0026rsquo;s get a baseline of what the original images look like and what the output of the untrained model is.\nTo look at the original images we can take the first training batch of 100 images and visualize them. Since we are initially using the flattened [784] image representation. We need to reshape it to the 28x28 image that we can recognize.\n(def my-batch (mx-io/next train-data)) (def images (mx-io/batch-data my-batch)) (ndarray/shape (ndarray/reshape (first images) [100 1 28 28])) (viz/im-sav {:title \u0026#34;originals\u0026#34; :output-path \u0026#34;results/\u0026#34; :x (ndarray/reshape (first images) [100 1 28 28])}) We can also do the same visualization with the test batch of data images by putting them into the predict-batch and using our model.\n;;; before training (def my-test-batch (mx-io/next test-data)) (def test-images (mx-io/batch-data my-test-batch)) (def preds (m/predict-batch model {:data test-images} )) (viz/im-sav {:title \u0026#34;before-training-preds\u0026#34; :output-path \u0026#34;results/\u0026#34; :x (ndarray/reshape (first preds) [100 1 28 28])}) They are not anything close to recognizable as numbers.\nTraining The next step is to train the model on the data. We set up a training function to step through all the batches of data.\n(def my-metric (eval-metric/mse)) (defn train [num-epochs] (doseq [epoch-num (range 0 num-epochs)] (println \u0026#34;starting epoch \u0026#34; epoch-num) (mx-io/do-batches train-data (fn [batch] (-\u0026gt; model (m/forward {:data (mx-io/batch-data batch) :label (mx-io/batch-data batch)}) (m/update-metric my-metric (mx-io/batch-data batch)) (m/backward) (m/update)))) (println \u0026#34;result for epoch \u0026#34; epoch-num \u0026#34; is \u0026#34; (eval-metric/get-and-reset my-metric)))) For each batch of 100 images it is doing the following:\nRun the forward pass of the model with both the data and label being the image Update the accuracy of the model with the mse (mean squared error metric) Do the backward computation Update the model according to the optimizer and the forward/backward computation. Let\u0026rsquo;s train it for 3 epochs.\nstarting epoch 0 result for epoch 0 is [mse 0.06460866] starting epoch 1 result for epoch 1 is [mse 0.033874355] starting epoch 2 result for epoch 2 is [mse 0.027255038] After training We can check the test images again and see if they look better.\n;;; after training (def my-test-batch (mx-io/next test-data)) (def test-images (mx-io/batch-data my-test-batch)) (def preds (m/predict-batch model {:data test-images} )) (viz/im-sav {:title \u0026#34;after-training-preds\u0026#34; :output-path \u0026#34;results/\u0026#34; :x (ndarray/reshape (first preds) [100 1 28 28])}) Much improved! They definitely look like numbers.\nWrap up We\u0026rsquo;ve made a simple autoencoder that can take images of digits and compress them down to a latent space representation the can later be decoded into the same image.\nIf you want to check out the full code for this example, you can find it here.\nStay tuned. We\u0026rsquo;ll take this example and build on it in future posts.\n","permalink":"https://gigasquidsoftware.com/blog/2019/08/16/simple-autoencoder/","summary":"\u003cp\u003e\u003ca data-flickr-embed=\"true\"  href=\"https://www.flickr.com/photos/horlik/2901925672/in/photolist-5qr8pf-qkv3m8-32RwmC-dZBC2B-ja8ch-48vDg-f56TGS-oUfNKn-652ZqG-QnCrbX-y3C828-jeGkmu-dxwE9L-jKaGtZ-haQ6j3-61w8UJ-WmitYz-tLymA-dZCHC4-CGvx3R-CC3GPE-BSxzda-eu625R-vHAgnk-cR7WAE-jZiLgu-BsZwLP-fhfvPT-dN1Rf9-o8Mkby-8zDocw-5DvC7S-CEij58-oaw922-akUgeW-ayQiGU-aay1vS-2fVFske-2eoRpCe-rqwa4o-9VJPtv-opgEcq-MDfFe-9yzUaK-4is9Z9-cutXnm-f9U23-L7hpoe-3i3H-enSJKf\" title=\"Perfect mirror\"\u003e\u003cimg src=\"https://live.staticflickr.com/3274/2901925672_325f5faeb8.jpg\" width=\"500\" height=\"364\" alt=\"Perfect mirror\"\u003e\u003c/a\u003e\u003cscript async src=\"//embedr.flickr.com/assets/client-code.js\" charset=\"utf-8\"\u003e\u003c/script\u003e\u003c/p\u003e\n\u003cp\u003e\u003cem\u003eIf you look long enough into the autoencoder, it looks back at you.\u003c/em\u003e\u003c/p\u003e\n\u003cp\u003eThe Autoencoder is a fun deep learning model to look into. Its goal is simple: given an input image, we would like to have the same output image.\u003c/p\u003e\n\u003cp\u003eIt\u0026rsquo;s sort of an identity function for deep learning models, but it is composed of two parts: an encoder and decoder, with the encoder translating the images to a \u003cem\u003elatent space representation\u003c/em\u003e and the encoder translating that back to a regular images that we can view.\u003c/p\u003e","title":"Simple Autoencoder"},{"content":"Spring is bringing some beautiful new things to the Clojure MXNet. Here are some highlights for the month of April.\nShipped We\u0026rsquo;ve merged 10 PRs over the last month. Many of them focus on core improvements to documentation and usability which is very important.\nThe MXNet project is also preparing a new release 1.4.1, so keep on the lookout for that to hit in the near future.\nClojure MXNet Made Simple Article Series Arthur Caillau added another post to his fantastic series - MXNet made simple: Pretrained Models for image classification - Inception and VGG\nCool Stuff in Development New APIs Great progress was made on the new version of the API for the Clojure NDArray and Symbol APIs by Kedar Bellare. We now have an experimental new version of the apis that are generated more directly from the C code so that we can have more control over the output.\nFor example the new version of the generated api for NDArray looks like:\n(defn activation \u0026#34;Applies an activation function element-wise to the input. The following activation functions are supported: - `relu`: Rectified Linear Unit, :math:`y = max(x, 0)` - `sigmoid`: :math:`y = \\\\frac{1}{1 + exp(-x)}` - `tanh`: Hyperbolic tangent, :math:`y = \\\\frac{exp(x) - exp(-x)}{exp(x) + exp(-x)}` - `softrelu`: Soft ReLU, or SoftPlus, :math:`y = log(1 + exp(x))` - `softsign`: :math:`y = \\\\frac{x}{1 + abs(x)}` Defined in src/operator/nn/activation.cc:L167 `data`: The input array. `act-type`: Activation function to be applied. `out`: Output array. (optional)\u0026#34; ([data act-type] (activation {:data data, :act-type act-type})) ([{:keys [data act-type out], :or {out nil}, :as opts}] (util/coerce-return (NDArrayAPI/Activation data act-type (util/-\u0026gt;option out))))) as opposed to:\n(defn activation ([\u0026amp; nd-array-and-params] (util/coerce-return (NDArray/Activation (util/coerce-param nd-array-and-params #{\u0026#34;scala.collection.Seq\u0026#34;}))))) So much nicer!!!\nBERT (State of the Art for NLP) We also have some really exciting examples for BERT in a PR that will be merged soon. If you are not familiar with BERT, this blog post is a good overview. Basically, it\u0026rsquo;s the state of the art in NLP right now. With the help of exported models from GluonNLP, we can do both inference and fine tuning of BERT models in MXNet with Clojure! This is an excellent example of cross fertilization across the GluonNLP, Scala, and Clojure MXNet projects.\nThere are two examples.\nBERT question and answer inference based off of a fine tuned model of the SQuAD Dataset in GluonNLP which is then exported. It allows one to actually do some natural language question and answering like: Question Answer Data {:input-answer \u0026#34;Rich Hickey is the creator of the Clojure language. Before Clojure, he developed dotLisp, a similar project based on the .NET platform, and three earlier attempts to provide interoperability between Lisp and Java: a Java foreign language interface for Common Lisp, A Foreign Object Interface for Lisp, and a Lisp-friendly interface to Java Servlets.\u0026#34;, :input-question \u0026#34;Who created Clojure?\u0026#34;, :ground-truth-answers [\u0026#34;rich\u0026#34; \u0026#34;hickey\u0026#34;]} Predicted Answer: [rich hickey] The second example is using the exported BERT base model and then fine tuning it in Clojure to do a task with sentence pair classification to see if two sentences are equivalent or not. The nice thing about this is that we were able to convert the existing tutorial in GluonNLP over to a Clojure Jupyter notebook with the lein-jupyter plugin. I didn\u0026rsquo;t realize that there is a nifty save-as command in Jupyter that can generate a markdown file, which makes for very handy documentation. Take a peek at the tutorial here. It might make its way into a blog post on its own in the next week or two.\nUpcoming Events I\u0026rsquo;ll be speaking about Clojure MXNet at the next Scicloj Event on May 15th at 10PM UTC. Please join us and get involved in making Clojure a great place for Data Science.\nI\u0026rsquo;m also really excited to attend ICLR in a couple weeks. It is a huge conference that I\u0026rsquo;m sure will melt my mind with the latest research in Deep Learning. If anyone else is planning to attend, please say hi :)\nGet Involved As always, we welcome involvement in the true Apache tradition. If you have questions or want to say hi, head on over the the closest #mxnet room on your preferred server. We are on Clojurian\u0026rsquo;s slack and Zulip\nCat Picture of the Month To close out, let\u0026rsquo;s take a lesson from my cats and don\u0026rsquo;t forget the importance of naps.\nHave a great rest of April!\n","permalink":"https://gigasquidsoftware.com/blog/2019/04/26/clojure-mxnet-april-update/","summary":"\u003cp\u003eSpring is bringing some beautiful new things to the  \u003ca href=\"http://mxnet.incubator.apache.org/\"\u003eClojure MXNet\u003c/a\u003e. Here are some highlights for the month of April.\u003c/p\u003e\n\u003ch2 id=\"shipped\"\u003eShipped\u003c/h2\u003e\n\u003cp\u003eWe\u0026rsquo;ve merged \u003ca href=\"https://github.com/apache/incubator-mxnet/pulls?utf8=%E2%9C%93\u0026amp;q=is%3Apr+is%3Aclosed+clojure\"\u003e10 PRs\u003c/a\u003e over the last month. Many of them focus on core improvements to documentation and usability which is very important.\u003c/p\u003e\n\u003cp\u003eThe MXNet project is also preparing a new release \u003ccode\u003e1.4.1\u003c/code\u003e, so keep on the lookout for that to hit in the near future.\u003c/p\u003e\n\u003ch2 id=\"clojure-mxnet-made-simple-article-series\"\u003eClojure MXNet Made Simple Article Series\u003c/h2\u003e\n\u003cp\u003e\u003ca href=\"https://arthurcaillau.com/about/\"\u003eArthur Caillau\u003c/a\u003e added another post to his fantastic series - \u003ca href=\"https://arthurcaillau.com/mxnet-made-simple-pretrained-models/\"\u003eMXNet made simple: Pretrained Models for image classification - Inception and VGG\u003c/a\u003e\u003c/p\u003e","title":"Clojure MXNet April Update"},{"content":"I\u0026rsquo;m starting a monthly update for Clojure MXNet. The goal is to share the progress and exciting things that are happening in the project and our community.\nHere\u0026rsquo;s some highlights for the month of March.\nShipped Under the shipped heading, the 1.4.0 release of MXNet has been released, along with the Clojure MXNet Jars. There have been improvements to the JVM memory management and an Image API addition. You can see the full list of changes here\nClojure MXNet Made Simple Article Series Arthur Caillau authored a really nice series of blog posts to help get people started with Clojure MXNet.\nGetting started with Clojure and MXNet on AWS MXNet made simple: Clojure NDArray API MXNet made simple: Clojure Symbol API MXNet made simple: Clojure Module API MXNet made simple: Clojure Symbol Visualization API MXNet made simple: Image Manipulation with OpenCV and MXNet Lein Template \u0026amp; Docker file Nicolas Modrzyk created a Leiningen template that allows you to easily get a MXNet project started - with a notebook too! It\u0026rsquo;s a great way to take Clojure MXNet for a spin\n# create project lein new clj-mxnet hello # run included sample lein run # start notebook engine lein notebook # open notebook http://0.0.0.0:10000/worksheet.html?filename=notes/practice.clj # open empty notebook with all namespaces http://0.0.0.0:10000/worksheet.html?filename=notes/empty.clj There also is a docker file as well\ndocker run -it -p 10000:10000 hellonico/mxnet After starting the container, you can open the same notebooks as above: # open notebook http://0.0.0.0:10000/worksheet.html?filename=notes/practice.clj # open empty notebook with all namespaces http://0.0.0.0:10000/worksheet.html?filename=notes/empty.clj Cool Stuff in Development There are a few really interesting things cooking for the future.\nOne is a PR for memory fixes from the Scala team that is getting really close to merging. This will be a solution to some the the memory problems that were encountered by early adopters of the Module API.\nAnother, is the new version of the API for the Clojure NDArray and Symbol APIs that is being spearheaded by Kedar Bellare\nFinally, work is being started to create a Gluon API for the Clojure package which is quite exciting.\nGet Involved As always, we welcome involvement in the true Apache tradition. If you have questions or want to say hi, head on over the the closest #mxnet room on your preferred server. We are on Clojurian\u0026rsquo;s slack and Zulip.\nCat Picture of the Month There is no better way to close out an update than a cat picture, so here is a picture of my family cat watching birds at the window.\nHave a great rest of March!\n","permalink":"https://gigasquidsoftware.com/blog/2019/03/22/clojure-mxnet-march-update/","summary":"\u003cp\u003eI\u0026rsquo;m starting a monthly update for \u003ca href=\"http://mxnet.incubator.apache.org/\"\u003eClojure MXNet\u003c/a\u003e. The goal is to share the progress and exciting things that are happening in the project and our community.\u003c/p\u003e\n\u003cp\u003eHere\u0026rsquo;s some highlights for the month of March.\u003c/p\u003e\n\u003ch2 id=\"shipped\"\u003eShipped\u003c/h2\u003e\n\u003cp\u003eUnder the shipped heading, the 1.4.0 release of MXNet has been released, along with the \u003ca href=\"https://search.maven.org/search?q=clojure%20mxnet\"\u003eClojure MXNet Jars\u003c/a\u003e. There have been improvements to the JVM memory management and an Image API addition. You can see the full list of changes \u003ca href=\"https://github.com/apache/incubator-mxnet/releases/tag/1.4.0#clojure\"\u003ehere\u003c/a\u003e\u003c/p\u003e","title":"Clojure MXNet March Update"},{"content":"\nObject detection just landed in MXNet thanks to the work of contributors Kedar Bellare and Nicolas Modrzyk. Kedar ported over the infer package to Clojure, making inference and prediction much easier for users and Nicolas integrated in his Origami OpenCV library into the the examples to make the visualizations happen.\nWe\u0026rsquo;ll walk through the main steps to use the infer object detection which include creating the detector with a model and then loading the image and running the inference on it.\nCreating the Detector To create the detector you need to define a couple of things:\nHow big is your image? What model are you going to be using for object detection? In the code below, we are going to be giving it an color image of size 512 x 512.\n(defn create-detector [] (let [descriptors [{:name \u0026#34;data\u0026#34; :shape [1 3 512 512] :layout layout/NCHW :dtype dtype/FLOAT32}] factory (infer/model-factory model-path-prefix descriptors)] (infer/create-object-detector factory))) The shape is going to be [1 3 512 512]. The 1 is for the batch size which in our case is a single image. The 3 is for the channels in the image which for a RGB image is 3 The 512 is for the image height and width. The layout specifies that the shape given is in terms of NCHW which is batch size, channel size, height, and width. The dtype is the image data type which will be the standard FLOAT32 The model-path-prefix points to the place where the trained model we are using for object detection lives. The model we are going to use is the Single Shot Multiple Box Object Detector (SSD). You can download the model yourself using this script.\nHow to Load an Image and Run the Detector Now that we have a model and a detector, we can load an image up and run the object detection.\nTo load the image use load-image which will load the image from the path.\n(infer/load-image-from-file input-image) Then run the detection using infer/detect-objects which will give you the top five predictions by default.\n(infer/detect-objects detector image) It will give an output something like this:\n[[{:class \u0026#34;person\u0026#34;, :prob 0.9657765, :x-min 0.021868259, :y-min 0.049295247, :x-max 0.9975169, :y-max 0.9734151} {:class \u0026#34;dog\u0026#34;, :prob 0.17513266, :x-min 0.16772352, :y-min 0.45792937, :x-max 0.55409217, :y-max 0.72507095} ... ]] which you can then use to draw bounding boxes on the image.\nTry Running the Example One of the best ways to explore using it is with the object detection example in the MXNet repo. It will be coming out officially in the 1.5.0 release, but you can get an early peek at it by building the project and running the example with the nightly snapshot.\nYou can do this by cloning the MXNet Repo and changing directory to contrib/clojure-package.\nNext, edit the project.clj to look like this:\n(defproject org.apache.mxnet.contrib.clojure/clojure-mxnet \u0026#34;1.5.0-SNAPSHOT\u0026#34; :description \u0026#34;Clojure package for MXNet\u0026#34; :url \u0026#34;https://github.com/apache/incubator-mxnet\u0026#34; :license {:name \u0026#34;Apache License\u0026#34; :url \u0026#34;http://www.apache.org/licenses/LICENSE-2.0\u0026#34;} :dependencies [[org.clojure/clojure \u0026#34;1.9.0\u0026#34;] [t6/from-scala \u0026#34;0.3.0\u0026#34;] ;; To use with nightly snapshot ;[org.apache.mxnet/mxnet-full_2.11-osx-x86_64-cpu \u0026#34;\u0026lt;insert-snapshot-version\u0026gt;\u0026#34;] ;[org.apache.mxnet/mxnet-full_2.11-linux-x86_64-cpu \u0026#34;\u0026lt;insert-snapshot-version\u0026gt;\u0026#34;] ;[org.apache.mxnet/mxnet-full_2.11-linux-x86_64-gpu \u0026#34;\u0026lt;insert-snapshot-version\u0026#34;] [org.apache.mxnet/mxnet-full_2.11-osx-x86_64-cpu \u0026#34;1.5.0-SNAPSHOT\u0026#34;] ;;; CI #_[org.apache.mxnet/mxnet-full_2.11 \u0026#34;INTERNAL\u0026#34;] [org.clojure/tools.logging \u0026#34;0.4.0\u0026#34;] [org.apache.logging.log4j/log4j-core \u0026#34;2.8.1\u0026#34;] [org.apache.logging.log4j/log4j-api \u0026#34;2.8.1\u0026#34;] [org.slf4j/slf4j-log4j12 \u0026#34;1.7.25\u0026#34; :exclusions [org.slf4j/slf4j-api]]] :pedantic? :skip :plugins [[lein-codox \u0026#34;0.10.3\u0026#34; :exclusions [org.clojure/clojure]] [lein-cloverage \u0026#34;1.0.10\u0026#34; :exclusions [org.clojure/clojure]] [lein-cljfmt \u0026#34;0.5.7\u0026#34;]] :codox {:namespaces [#\u0026#34;^org\\.apache\\.clojure-mxnet\\.(?!gen).*\u0026#34;]} :aot [dev.generator] :repositories [[\u0026#34;staging\u0026#34; {:url \u0026#34;https://repository.apache.org/content/repositories/staging\u0026#34; :snapshots true :update :always}] [\u0026#34;snapshots\u0026#34; {:url \u0026#34;https://repository.apache.org/content/repositories/snapshots\u0026#34; :snapshots true :update :always}]]) If you are running on linux, you should change the mxnet-full_2.11-osx-x86_64-cpu to mxnet-full_2.11-linux-x86_64-cpu.\nNext, go ahead and do lein test to make sure that everything builds ok. If you run into any trouble please refer to README for any missing dependencies.\nAfter that do a lein install to install the clojure-mxnet jar to your local maven. Now you are ready to cd examples/infer/object-detection to try it out. Refer to the README for more details.\nIf you run into any problems getting started, feel free to reach out in the Clojurian #mxnet slack room or open an issue at the MXNet project. We are a friendly group and happy to help out.\nThanks again to the community for the contributions to make this possible. It\u0026rsquo;s great seeing new things coming to life.\nHappy Object Detecting!\n","permalink":"https://gigasquidsoftware.com/blog/2019/01/19/object-detection-with-clojure-mxnet/","summary":"\u003cp\u003e\u003cimg loading=\"lazy\" src=\"https://c1.staticflickr.com/8/7837/32928474208_4960caafb3.jpg\"\u003e\u003c/p\u003e\n\u003cp\u003eObject detection just landed in MXNet thanks to the work of contributors \u003ca href=\"https://github.com/kedarbellare\"\u003eKedar Bellare\u003c/a\u003e and \u003ca href=\"https://github.com/hellonico/\"\u003eNicolas Modrzyk\u003c/a\u003e. Kedar ported over the \u003ccode\u003einfer\u003c/code\u003e package to Clojure, making inference and prediction much easier for users and Nicolas integrated in his \u003ca href=\"https://github.com/hellonico/origami\"\u003eOrigami\u003c/a\u003e OpenCV library into the the examples to make the visualizations happen.\u003c/p\u003e\n\u003cp\u003eWe\u0026rsquo;ll walk through the main steps to use the \u003ccode\u003einfer\u003c/code\u003e object detection which include creating the detector with a model and then loading the image and running the inference on it.\u003c/p\u003e","title":"Object Detection with Clojure MXNet"},{"content":"It\u0026rsquo;s holiday time and that means parties and getting together with friends. Bringing a baked good or dessert to a gathering is a time honored tradition. But what if this year, you could take it to the next level? Everyone brings actual food. But with the help of Deep Learning, you can bring something completely different - you can bring the image of baked good! I\u0026rsquo;m not talking about just any old image that someone captured with a camera or created with a pen and paper. I\u0026rsquo;m talking about the computer itself creating. This image would be never before seen, totally unique, and crafted by the creative process of the machine.\nThat is exactly what we are going to do. We are going to create a flan\nIf you\u0026rsquo;ve never had a flan before, it\u0026rsquo;s a yummy dessert made of a baked custard with caramel sauce on it.\n\u0026ldquo;Why a flan?\u0026rdquo;, you may ask. There are quite a few reasons:\nIt\u0026rsquo;s tasty in real life. Flan rhymes with GAN, (unless you pronounce it \u0026ldquo;Gaaahn\u0026rdquo;). Why not? Onto the recipe. How are we actually going to make this work? We need some ingredients:\nClojure - the most advanced programming language to create generative desserts. Apache MXNet - a flexible and efficient deep learning library that has a Clojure package. 1000-5000 pictures of flans - for Deep Learning you need data! Gather Flan Pictures The first thing you want to do is gather your 1000 or more images with a scraper. The scraper will crawl google, bing, or instagram and download pictures of mostly flans to your computer. You may have to eyeball and remove any clearly wrong ones from your stash.\nNext, you need to gather all these images in a directory and run a tool called im2rec.py on them to turn them into an image record iterator for use with MXNet. This will produce an optimized format that will allow our deep learning program to efficiently cycle through them.\nRun:\npython3 im2rec.py --resize 28 root flan to produce a flan.rec file with images resized to 28x28 that we can use next.\nLoad Flan Pictures into MXNet The next step is to import the image record iterator into the MXNet with the Clojure API. We can do this with the io namespace.\nAdd this to your require:\n[org.apache.clojure-mxnet.io :as mx-io] Now, we can load our images:\n(def flan-iter (mx-io/image-record-iter {:path-imgrec \u0026#34;flan.rec\u0026#34; :data-shape [3 28 28] :batch-size batch-size})) Now, that we have the images, we need to create our model. This is what is actually going to do the learning and creating of images.\nCreating a GAN model. GAN stands for Generative Adversarial Network. This is a incredibly cool deep learning technique that has two different models pitted against each, yet both learning and getting better at the same time. The two models are a generator and a discriminator. The generator model creates a new image from a random noise vector. The discriminator then tries to tell whether the image is a real image or a fake image. We need to create both of these models for our network.\nFirst, the discriminator model. We are going to use the symbol namespace for the clojure package:\n(defn discriminator [] (as-\u0026gt; (sym/variable \u0026#34;data\u0026#34;) data (sym/convolution \u0026#34;d1\u0026#34; {:data data :kernel [4 4] :pad [3 3] :stride [2 2] :num-filter ndf :no-bias true}) (sym/batch-norm \u0026#34;dbn1\u0026#34; {:data data :fix-gamma true :eps eps}) (sym/leaky-re-lu \u0026#34;dact1\u0026#34; {:data data :act-type \u0026#34;leaky\u0026#34; :slope 0.2}) ... There is a variable for the data coming in, (which is the picture of the flan), it then flows through the other layers which consist of convolutions, normalization, and activation layers. The last three layers actually repeat another two times before ending in the output, which tells whether it thinks the image was a fake or not.\nThe generator model looks similar:\n(defn generator [] (as-\u0026gt; (sym/variable \u0026#34;rand\u0026#34;) data (sym/deconvolution \u0026#34;g1\u0026#34; {:data data :kernel [4 4] :pad [0 0] :stride [1 1] :num-filter (* 4 ndf) :no-bias true}) (sym/batch-norm \u0026#34;gbn1\u0026#34; {:data data :fix-gamma true :eps eps}) (sym/activation \u0026#34;gact1\u0026#34; {:data data :act-type \u0026#34;relu\u0026#34;}) ... There is a variable for the data coming in, but this time it is a random noise vector. Another interesting point that is is using a deconvolution layer instead of a convolution layer. The generator is basically the inverse of the discriminator. It starts with a random noise vector, but that is translated up through the layers until it is expanded to a image output.\nNext, we iterate through all of our training images in our flan-iter with reduce-batches. Here is just an excerpt where we get a random noise vector and have the generator run the data through and produce the output image:\n(mx-io/reduce-batches flan-iter (fn [n batch] (let [rbatch (mx-io/next rand-noise-iter) dbatch (mapv normalize-rgb-ndarray (mx-io/batch-data batch)) out-g (-\u0026gt; mod-g (m/forward rbatch) (m/outputs)) The whole code is here for reference, but let\u0026rsquo;s skip forward and run it and see what happens.\nFLANS!! Well, they could be flans if you squint a bit.\nNow that we have them kinda working for a small image size 28x28, let\u0026rsquo;s biggerize it.\nTurn on the Oven and Bake Turning up the size to 128x128 requires some alterations in the layers\u0026rsquo; parameters to make sure that it processes and generates the correct size, but other than that we are good to go.\nHere comes the fun part, watching it train and learn:\nEpoch 0 In the beginning there was nothing but random noise.\nEpoch 10 It\u0026rsquo;s beginning to learn colors! Red, yellow, brown seem to be important to flans.\nEpoch 23 It\u0026rsquo;s learning shapes! It has learned that flans seem to be blob shaped.\nEpoch 33 It is moving into its surreal phase. Salvidor Dali would be proud of these flans.\nEpoch 45 Things take a weird turn. Does that flan have eyes?\nEpoch 68 Even worse. Are those demonic flans? Should we even continue down this path?\nAnswer: Yes - the training must go on..\nEpoch 161 Big moment here. It looks like something that could possibly be edible.\nEpoch 170 Ick! Green Flans! No one is going to want that.\nEpoch 195 We\u0026rsquo;ve achieved maximum flan, (for the time being).\nExplore If you are interested in playing around with the pretrained model, you can check it out here with the pretrained function. It will load up the trained model and generate flans for you to explore and bring to your dinner parties.\nWrapping up, training GANs is a lot of fun. With MXNet, you can bring the fun with you to Clojure.\nWant more, check out this Clojure Conj video - Can You GAN?.\n","permalink":"https://gigasquidsoftware.com/blog/2018/12/18/how-to-gan-a-flan/","summary":"\u003cp\u003eIt\u0026rsquo;s holiday time and that means parties and getting together with friends. Bringing a baked good or dessert to a gathering is a time honored tradition. But what if this year, you could take it to the next level? Everyone brings actual food. But with the help of Deep Learning, you can bring something completely different -  you can bring the \u003cem\u003eimage\u003c/em\u003e of baked good! I\u0026rsquo;m not talking about just any old image that someone captured with a camera or created with a pen and paper. I\u0026rsquo;m talking about the computer itself \u003cstrong\u003ecreating\u003c/strong\u003e. This image would be never before seen, totally unique, and crafted by the creative process of the machine.\u003c/p\u003e","title":"How to GAN a Flan"},{"content":"\nThis is an introduction to the high level Clojure API for deep learning library MXNet.\nThe module API provides an intermediate and high-level interface for performing computation with neural networks in MXNet.\nTo follow along with this documentation, you can use this namespace to with the needed requires:\n(ns docs.module (:require [clojure.java.io :as io] [clojure.java.shell :refer [sh]] [org.apache.clojure-mxnet.eval-metric :as eval-metric] [org.apache.clojure-mxnet.io :as mx-io] [org.apache.clojure-mxnet.module :as m] [org.apache.clojure-mxnet.symbol :as sym] [org.apache.clojure-mxnet.ndarray :as ndarray])) Prepare the Data In this example, we are going to use the MNIST data set. If you have cloned the MXNet repo and cd contrib/clojure-package, we can run some helper scripts to download the data for us.\n(def data-dir \u0026#34;data/\u0026#34;) (when-not (.exists (io/file (str data-dir \u0026#34;train-images-idx3-ubyte\u0026#34;))) (sh \u0026#34;../../scripts/get_mnist_data.sh\u0026#34;)) MXNet provides function in the io namespace to load the MNIST datasets into training and test data iterators that we can use with our module.\n(def train-data (mx-io/mnist-iter {:image (str data-dir \u0026#34;train-images-idx3-ubyte\u0026#34;) :label (str data-dir \u0026#34;train-labels-idx1-ubyte\u0026#34;) :label-name \u0026#34;softmax_label\u0026#34; :input-shape [784] :batch-size 10 :shuffle true :flat true :silent false :seed 10})) (def test-data (mx-io/mnist-iter {:image (str data-dir \u0026#34;t10k-images-idx3-ubyte\u0026#34;) :label (str data-dir \u0026#34;t10k-labels-idx1-ubyte\u0026#34;) :input-shape [784] :batch-size 10 :flat true :silent false})) Preparing a Module for Computation To construct a module, we need to have a symbol as input. This symbol takes input data in the first layer and then has subsequent layers of fully connected and relu activation layers, ending up in a softmax layer for output.\n(let [data (sym/variable \u0026#34;data\u0026#34;) fc1 (sym/fully-connected \u0026#34;fc1\u0026#34; {:data data :num-hidden 128}) act1 (sym/activation \u0026#34;relu1\u0026#34; {:data fc1 :act-type \u0026#34;relu\u0026#34;}) fc2 (sym/fully-connected \u0026#34;fc2\u0026#34; {:data act1 :num-hidden 64}) act2 (sym/activation \u0026#34;relu2\u0026#34; {:data fc2 :act-type \u0026#34;relu\u0026#34;}) fc3 (sym/fully-connected \u0026#34;fc3\u0026#34; {:data act2 :num-hidden 10}) out (sym/softmax-output \u0026#34;softmax\u0026#34; {:data fc3})] out) ;=\u0026gt;#object[org.apache.mxnet.Symbol 0x1f43a406 \u0026#34;org.apache.mxnet.Symbol@1f43a406\u0026#34;] You can also write this with the as-\u0026gt; threading macro.\n(def out (as-\u0026gt; (sym/variable \u0026#34;data\u0026#34;) data (sym/fully-connected \u0026#34;fc1\u0026#34; {:data data :num-hidden 128}) (sym/activation \u0026#34;relu1\u0026#34; {:data data :act-type \u0026#34;relu\u0026#34;}) (sym/fully-connected \u0026#34;fc2\u0026#34; {:data data :num-hidden 64}) (sym/activation \u0026#34;relu2\u0026#34; {:data data :act-type \u0026#34;relu\u0026#34;}) (sym/fully-connected \u0026#34;fc3\u0026#34; {:data data :num-hidden 10}) (sym/softmax-output \u0026#34;softmax\u0026#34; {:data data}))) ;=\u0026gt; #\u0026#39;tutorial.module/out By default, context is the CPU. If you need data parallelization, you can specify a GPU context or an array of GPU contexts like this (m/module out {:contexts [(context/gpu)]})\nBefore you can compute with a module, you need to call bind to allocate the device memory and init-params or set-params to initialize the parameters. If you simply want to fit a module, you don’t need to call bind and init-params explicitly, because the fit function automatically calls them if they are needed.\n(let [mod (m/module out)] (-\u0026gt; mod (m/bind {:data-shapes (mx-io/provide-data train-data) :label-shapes (mx-io/provide-label train-data)}) (m/init-params))) Now you can compute with the module using functions like forward, backward, etc.\nTraining and Predicting Modules provide high-level APIs for training, predicting, and evaluating. To fit a module, call the fit function with some data iterators:\n(def mod (m/fit (m/module out) {:train-data train-data :eval-data test-data :num-epoch 1})) ;; Epoch 0 Train- [accuracy 0.12521666] ;; Epoch 0 Time cost- 8392 ;; Epoch 0 Validation- [accuracy 0.2227] You can pass in batch-end callbacks using batch-end-callback and epoch-end callbacks using epoch-end-callback in the fit-params. You can also set parameters using functions like in the fit-params like optimizer and eval-metric. To learn more about the fit-params, see the fit-param function options. To predict with a module, call predict with a DataIter:\n(def results (m/predict mod {:eval-data test-data})) (first results) ;=\u0026gt;#object[org.apache.mxnet.NDArray 0x3540b6d3 \u0026#34;org.apache.mxnet.NDArray@a48686ec\u0026#34;] (first (ndarray/-\u0026gt;vec (first results))) ;=\u0026gt;0.08261358 The module collects and returns all of the prediction results. For more details about the format of the return values, see the documentation for the predict function.\nWhen prediction results might be too large to fit in memory, use the predict-every-batch API.\n(let [preds (m/predict-every-batch mod {:eval-data test-data})] (mx-io/reduce-batches test-data (fn [i batch] (println (str \u0026#34;pred is \u0026#34; (first (get preds i)))) (println (str \u0026#34;label is \u0026#34; (mx-io/batch-label batch))) ;;; do something (inc i)))) If you need to evaluate on a test set and don’t need the prediction output, call the score function with a data iterator and an eval metric:\n(m/score mod {:eval-data test-data :eval-metric (eval-metric/accuracy)}) ;=\u0026gt;[\u0026#34;accuracy\u0026#34; 0.2227] This runs predictions on each batch in the provided data iterator and computes the evaluation score using the provided eval metric. The evaluation results are stored in metric so that you can query later.\nSaving and Loading To save the module parameters in each training epoch, use a checkpoint function:\n(let [save-prefix \u0026#34;my-model\u0026#34;] (doseq [epoch-num (range 3)] (mx-io/do-batches train-data (fn [batch ;; do something ])) (m/save-checkpoint mod {:prefix save-prefix :epoch epoch-num :save-opt-states true}))) ;; INFO org.apache.mxnet.module.Module: Saved checkpoint to my-model-0000.params ;; INFO org.apache.mxnet.module.Module: Saved optimizer state to my-model-0000.states ;; INFO org.apache.mxnet.module.Module: Saved checkpoint to my-model-0001.params ;; INFO org.apache.mxnet.module.Module: Saved optimizer state to my-model-0001.states ;; INFO org.apache.mxnet.module.Module: Saved checkpoint to my-model-0002.params ;; INFO org.apache.mxnet.module.Module: Saved optimizer state to my-model-0002.states To load the saved module parameters, call the load-checkpoint function:\n(def new-mod (m/load-checkpoint {:prefix \u0026#34;my-model\u0026#34; :epoch 1 :load-optimizer-states true})) new-mod ;=\u0026gt; #object[org.apache.mxnet.module.Module 0x5304d0f4 \u0026#34;org.apache.mxnet.module.Module@5304d0f4\u0026#34;] To initialize parameters, Bind the symbols to construct executors first with bind function. Then, initialize the parameters and auxiliary states by calling init-params function.\n(-\u0026gt; new-mod (m/bind {:data-shapes (mx-io/provide-data train-data) :label-shapes (mx-io/provide-label train-data)}) (m/init-params)) To get current parameters, use params\n(let [[arg-params aux-params] (m/params new-mod)] {:arg-params arg-params :aux-params aux-params}) ;; {:arg-params ;; {\u0026#34;fc3_bias\u0026#34; ;; #object[org.apache.mxnet.NDArray 0x39adc3b0 \u0026#34;org.apache.mxnet.NDArray@49caf426\u0026#34;], ;; \u0026#34;fc2_weight\u0026#34; ;; #object[org.apache.mxnet.NDArray 0x25baf623 \u0026#34;org.apache.mxnet.NDArray@a6c8f9ac\u0026#34;], ;; \u0026#34;fc1_bias\u0026#34; ;; #object[org.apache.mxnet.NDArray 0x6e089973 \u0026#34;org.apache.mxnet.NDArray@9f91d6eb\u0026#34;], ;; \u0026#34;fc3_weight\u0026#34; ;; #object[org.apache.mxnet.NDArray 0x756fd109 \u0026#34;org.apache.mxnet.NDArray@2dd0fe3c\u0026#34;], ;; \u0026#34;fc2_bias\u0026#34; ;; #object[org.apache.mxnet.NDArray 0x1dc69c8b \u0026#34;org.apache.mxnet.NDArray@d128f73d\u0026#34;], ;; \u0026#34;fc1_weight\u0026#34; ;; #object[org.apache.mxnet.NDArray 0x20abc769 \u0026#34;org.apache.mxnet.NDArray@b8e1c5e8\u0026#34;]}, ;; :aux-params {}} To assign parameter and aux state values, use set-params function.\n(m/set-params new-mod {:arg-params (m/arg-params new-mod) :aux-params (m/aux-params new-mod)}) ;=\u0026gt; #object[org.apache.mxnet.module.Module 0x5304d0f4 \u0026#34;org.apache.mxnet.module.Module@5304d0f4\u0026#34;] To resume training from a saved checkpoint, instead of calling set-params, directly call fit, passing the loaded parameters, so that fit knows to start from those parameters instead of initializing randomly\nCreate fit-params, and then use it to set begin-epoch so that fit knows to resume from a saved epoch.\n;; reset the training data before calling fit or you will get an error (mx-io/reset train-data) (mx-io/reset test-data) (m/fit new-mod {:train-data train-data :eval-data test-data :num-epoch 2 :fit-params (-\u0026gt; (m/fit-params {:begin-epoch 1}))}) If you are interested in checking out MXNet and exploring on your own, check out the main page here with instructions on how to install and other information.\nSee other blog posts about MXNet Clojure MXNet - NDArray Clojure MXNet Joins Apache MXNet ","permalink":"https://gigasquidsoftware.com/blog/2018/07/05/clojure-mxnet-the-module-api/","summary":"\u003cp\u003e\u003cimg loading=\"lazy\" src=\"https://cdn-images-1.medium.com/max/800/1*OoqsrMD7JzXAvRUGx_8_fg.jpeg\"\u003e\u003c/p\u003e\n\u003cp\u003eThis is an introduction to the high level Clojure API for deep learning library \u003ca href=\"http://mxnet.incubator.apache.org/\"\u003eMXNet\u003c/a\u003e.\u003c/p\u003e\n\u003cp\u003eThe module API provides an intermediate and high-level interface for performing computation with neural networks in MXNet.\u003c/p\u003e\n\u003cp\u003eTo follow along with this documentation, you can use this namespace to with the needed requires:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-clojure\" data-lang=\"clojure\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e(\u003cspan style=\"color:#66d9ef\"\u003ens \u003c/span\u003edocs.module\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  (\u003cspan style=\"color:#e6db74\"\u003e:require\u003c/span\u003e [clojure.java.io \u003cspan style=\"color:#e6db74\"\u003e:as\u003c/span\u003e io]\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            [clojure.java.shell \u003cspan style=\"color:#e6db74\"\u003e:refer\u003c/span\u003e [sh]]\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            [org.apache.clojure-mxnet.eval-metric \u003cspan style=\"color:#e6db74\"\u003e:as\u003c/span\u003e eval-metric]\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            [org.apache.clojure-mxnet.io \u003cspan style=\"color:#e6db74\"\u003e:as\u003c/span\u003e mx-io]\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            [org.apache.clojure-mxnet.module \u003cspan style=\"color:#e6db74\"\u003e:as\u003c/span\u003e m]\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            [org.apache.clojure-mxnet.symbol \u003cspan style=\"color:#e6db74\"\u003e:as\u003c/span\u003e sym]\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            [org.apache.clojure-mxnet.ndarray \u003cspan style=\"color:#e6db74\"\u003e:as\u003c/span\u003e ndarray]))\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch2 id=\"prepare-the-data\"\u003ePrepare the Data\u003c/h2\u003e\n\u003cp\u003eIn this example, we are going to use the MNIST data set. If you have cloned the MXNet repo and \u003ccode\u003ecd contrib/clojure-package\u003c/code\u003e, we can run some helper scripts to download the data for us.\u003c/p\u003e","title":"Clojure MXNet - The Module API"},{"content":"\nI\u0026rsquo;m delighted to share the news that the Clojure package for MXNet has now joined the main Apache MXNet project. A big thank you to the efforts of everyone involved to make this possible. Having it as part of the main project is a great place for growth and collaboration that will benefit both MXNet and the Clojure community.\nInvitation to Join and Contribute The Clojure package has been brought in as a contrib clojure-package. It is still very new and will go through a period of feedback, stabilization, and improvement before it graduates out of contrib.\nWe welcome contributors and people getting involved to make it better.\nAre you interested in Deep Learning and Clojure? Great - Join us!\nThere are a few ways to get involved.\nCheck out the current state of the Clojure package some contribution needs here https://cwiki.apache.org/confluence/display/MXNET/Clojure+Package+Contribution+Needs Join the Clojurian Slack #mxnet channel Join the MXNet dev mailing list by sending an email to dev-subscribe@mxnet.apache.org.. Join the MXNET Slack channel - You have to join the MXnet dev mailing list first, but after that says you would like to join the slack and someone will add you. Join the MXNet Discussion Forum Want to Learn More? There are lots of examples in the package to check out, but a good place to start are the tutorials here https://github.com/apache/incubator-mxnet/tree/master/contrib/clojure-package/examples/tutorial\nThere is a blog walkthough here as well - Clojure MXNet Module API\n","permalink":"https://gigasquidsoftware.com/blog/2018/07/01/clojure-mxnet-joins-the-apache-mxnet-project/","summary":"\u003cp\u003e\u003cimg loading=\"lazy\" src=\"https://cdn-images-1.medium.com/max/800/1*OoqsrMD7JzXAvRUGx_8_fg.jpeg\"\u003e\u003c/p\u003e\n\u003cp\u003eI\u0026rsquo;m delighted to share the news that the Clojure package for \u003ca href=\"https://mxnet.apache.org/\"\u003eMXNet\u003c/a\u003e has now joined the main Apache MXNet project. A big thank you to the efforts of everyone involved to make this possible. Having it as part of the main project is a great place for growth and collaboration that will benefit both MXNet and the Clojure community.\u003c/p\u003e\n\u003ch2 id=\"invitation-to-join-and-contribute\"\u003eInvitation to Join and Contribute\u003c/h2\u003e\n\u003cp\u003eThe Clojure package has been brought in as a \u003cem\u003econtrib\u003c/em\u003e \u003ca href=\"https://github.com/apache/incubator-mxnet/tree/master/contrib/clojure-package\"\u003eclojure-package\u003c/a\u003e. It is still very new and will go through a period of feedback, stabilization, and improvement before it graduates out of contrib.\u003c/p\u003e","title":"Clojure MXNet Joins the Apache MXNet Project"},{"content":"\nThis is the beginning of a series of blog posts to get to know the Apache MXNet Deep Learning project and the new Clojure language binding clojure-package\nMXNet is a first class, modern deep learning library that AWS has officially picked as its chosen library. It supports multiple languages on a first class basis and is incubating as an Apache project.\nThe motivation for creating a Clojure package is to be able to open the deep learning library to the Clojure ecosystem and build bridges for future development and innovation for the community. It provides all the needed tools including low level and high level apis, dynamic graphs, and things like GAN and natural language support.\nSo let\u0026rsquo;s get on with our introduction with one of the basic building blocks of MXNet, the NDArray.\nMeet NDArray The NDArray is the tensor data structure in MXNet. Let\u0026rsquo;s start of by creating one. First we need to require the ndarray namespace:\n(ns tutorial.ndarray (:require [org.apache.clojure-mxnet.ndarray :as ndarray])) Now let\u0026rsquo;s create an all zero array of dimension 100 x 50\n(ndarray/zeros [100 50]) ;=\u0026gt; #object[org.apache.mxnet.NDArray 0x3e396d0 \u0026#34;org.apache.mxnet.NDArray@aeea40b6\u0026#34;] We can check the shape of this by using shape-vec\n(ndarray/shape-vec (ndarray/zeros [100 50])) ;=\u0026gt; [100 50] There is also a quick way to create an ndarray of ones with the ones function:\n(ndarray/ones [256 32 128 1]) Ones and zeros are nice, but what an array with specific contents? There is an array function for that. Specific the contents of the array first and the shape second:\n(def c (ndarray/array [1 2 3 4 5 6] [2 3])) (ndarray/shape-vec c) ;=\u0026gt; [2 3] To convert it back to a vector format, we can use the -\u0026gt;vec function.\n(ndarray/-\u0026gt;vec c) ;=\u0026gt; [1.0 2.0 3.0 4.0 5.0 6.0] Now that we know how to create NDArrays, we can get to do something interesting like operations on them.\nOperations There are all the standard arithmetic operations:\n(def a (ndarray/ones [1 5])) (def b (ndarray/ones [1 5])) (-\u0026gt; (ndarray/+ a b) (ndarray/-\u0026gt;vec)) ;=\u0026gt; [2.0 2.0 2.0 2.0 2.0] Note that the original ndarrays are unchanged.\n(ndarray/-\u0026gt;vec a) ;=\u0026gt; [1.0 1.0 1.0 1.0 1.0] (ndarray/-\u0026gt;vec b) ;=\u0026gt; [1.0 1.0 1.0 1.0 1.0] But, we can change that if we use the inplace operators:\n(ndarray/+= a b) (ndarray/-\u0026gt;vec a) ;=\u0026gt; [2.0 2.0 2.0 2.0 2.0] There are many more operations, but just to give you a taste, we\u0026rsquo;ll take a look a the dot product operation:\n(def arr1 (ndarray/array [1 2] [1 2])) (def arr2 (ndarray/array [3 4] [2 1])) (def res (ndarray/dot arr1 arr2)) (ndarray/shape-vec res) ;=\u0026gt; [1 1] (ndarray/-\u0026gt;vec res) ;=\u0026gt; [11.0] If you are curious about the other operators available in NDArray API check out the MXNet project documentation page\nNow that we have ndarrays and can do calculations on them, we might want to save and load them.\nSaving and Loading You can save ndarrays with a name as a map like:\n(ndarray/save \u0026#34;filename\u0026#34; {\u0026#34;arr1\u0026#34; arr1 \u0026#34;arr2\u0026#34; arr2}) To load them, you just specify the filename and the map is returned.\n(ndarray/load \u0026#34;filename\u0026#34;) ;=\u0026gt; {\u0026#34;arr1\u0026#34; #object[org.apache.mxnet.NDArray 0x1b629ff4 \u0026#34;org.apache.mxnet.NDArray@63da08cb\u0026#34;] ;=\u0026gt; \u0026#34;arr2\u0026#34; #object[org.apache.mxnet.NDArray 0x25d994e3 \u0026#34;org.apache.mxnet.NDArray@5bbaf2c3\u0026#34;]} One more cool thing, we can even due our operations on the cpu or gpu.\nMulti-Device Support When creating an ndarray you can use a context argument to specify the device. To do this, we will need the help of the context namespace.\n(require \u0026#39;[org.apache.clojure-mxnet.context :as context]) By default, the ndarray is created on the cpu context.\n(def cpu-a (ndarray/zeros [100 200])) (ndarray/context cpu-a) ;=\u0026gt; #object[ml.dmlc.mxnet.Context 0x3f376123 \u0026#34;cpu(0)\u0026#34;] But we can specify the gpu instead, (if we have a gpu enabled build).\n(def gpu-b (ndarray/zeros [100 200] {:ctx (context/gpu 0)})) Note: Operations among different contexts are currently not allowed, but there is a copy-to function that can help copy the content from one device to another and then continue on with the computation.\nWrap up I hope you\u0026rsquo;ve enjoyed the brief introduction to the MXNet library, there is much more to explore in future posts. If you are interested in giving it a try, there are native jars for OSX cpu and Linux cpu/gpu available and the code for the ndarray tutorial can be found here\nPlease remember that the library is in a experimential state, so if you encounter any problems or have any other feedback, please log an issue so bugs and rough edges can be fixed :).\n","permalink":"https://gigasquidsoftware.com/blog/2018/06/03/meet-clojure-mxnet-ndarray/","summary":"\u003cp\u003e\u003cimg loading=\"lazy\" src=\"https://cdn-images-1.medium.com/max/800/1*OoqsrMD7JzXAvRUGx_8_fg.jpeg\"\u003e\u003c/p\u003e\n\u003cp\u003eThis is the beginning of a series of blog posts to get to know the \u003ca href=\"https://mxnet.apache.org/\"\u003eApache MXNet\u003c/a\u003e Deep Learning project and the new Clojure language binding \u003ca href=\"https://github.com/apache/incubator-mxnet/tree/master/contrib/clojure-package\"\u003eclojure-package\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003eMXNet is a first class, modern deep learning library that AWS has officially picked as its chosen library. It supports multiple languages on a first class basis and is incubating as an Apache project.\u003c/p\u003e\n\u003cp\u003eThe motivation for creating a Clojure package is to be able to open the deep learning library to the Clojure ecosystem and build bridges for future development and innovation for the community. It provides all the needed tools including low level and high level apis, dynamic graphs, and things like GAN and natural language support.\u003c/p\u003e","title":"Meet Clojure MXNet - NDArray"},{"content":"I was 10 years into my career when I met her. I could count the number of other women programmers I had worked with on one hand and none of them had young children at home like me. She was not only incredibly experienced and competent, but also had a son in college. I was curious about her career path so I asked her one day at lunch why she was still programming and hadn’t become a manager instead.\nShe smiled at me kindly and replied, \u0026ldquo;I’ve worked very hard to stay exactly where I am\u0026rdquo;, and I was enlightened.\n","permalink":"https://gigasquidsoftware.com/blog/2018/03/04/on-staying-technical/","summary":"\u003cp\u003eI was 10 years into my career when I met her. I could count the number of other women programmers I had worked with on one hand and none of them had young children at home like me. She was not only incredibly experienced and competent, but also had a son in college. I was curious about her career path so I asked her one day at lunch why she was still programming and hadn’t become a manager instead.\u003c/p\u003e","title":"On Staying Technical"},{"content":"I wrote a blog post a while back about using a Clojure machine learning library called Cortex to do the Kaggle Cats and Dogs classification challenge.\nI wanted to revisit it for a few reasons. The first one is that the Cortex library has progressed and improved considerably over the last year. It\u0026rsquo;s still not at version 1.0, but it my eyes, it\u0026rsquo;s really starting to shine. The second reason is that they recently published an example of using the RESNET50 model, (I\u0026rsquo;ll explain later on), to do fine-tuning or transfer learning. The third reason, is that there is a great new plugin for leiningen the supports using Jupyter notebooks with Clojure projects. These notebooks are a great way of doing walkthroughs and tutorials.\nPutting all these things together, I felt like I was finally at a stage where I could somewhat replicate the first lesson in the Practical Deep Learning Course for Coders with Cats and Dogs - although this time all in Clojure!\nWhere to Start? In the last blog post, we created our deep learning network and trained the data on scaled down images (like 50x50) from scratch. This time we are much smarter.\nWe are still of course going to have to get a hold of all the training data from Kaggle Cats vs Dogs Challenge. The big difference is this time, we are just going to have to train our model for 1 epoch. What\u0026rsquo;s more, the results will be way better than before.\nHow is this possible? We are going to use an already trained model, RESNET50. This model has already been painstakingly trained with a gigantic network that is 50 layers deep on the ImageNet challenge. That\u0026rsquo;s a challenge that has models try to classify a 1000 different categories. The theory is that the inner layers of the network have already learned about the features that make up cats and dogs, all we would need to do is peel off the final layer of the network and graft on a new layers that just learns the final classification for our 2 categories of cats and dogs. This is called transfer learning or retraining.\nPlan of Action Get all the cats and dogs pictures in the right directory format for training Train the model with all but the last layer in the RESNET model. The last layer we are going to replace with our own layer that will finetune it to classify only cats and dogs Run the test data and come up with a spreadsheet of results to submit to Kaggle. Getting all the data pictures in the right format This is the generally the most time consuming step of most deep learning. I\u0026rsquo;ll spare you the gritty details but we want to get all the pictures from the train.zip into the format\n-data -cats-dogs-training -cat 1110.png ... -dog 12416.png ... -cats-dogs-testing -cat 11.png ... -dog 12.png ... The image sizes must also all be resized to match the input of the RESNET50. That means they all have to be 224x224.\nTrain the model The cortex functions allow you to load the resnet50 model, remove the last layer, freeze all the other layers so that they will not be retrained, and add new layers.\nI was surprised that I could actually train the model with all the images at 224x244 with the huge RESNET50 model. I built the uberjar and ran it which helped the performance.\nlein uberjar\njava -jar target/cats-dogs-cortex-redux.jar\nTraining one epoch took me approximately 6 minutes. Not bad, especially considering that\u0026rsquo;s all the training I really needed to do.\nLoss for epoch 1: (current) 0.05875186542016347 (best) null Saving network to trained-network.nippy The key point is that it saved the fine tuned network to trained-network.nippy\nRun the Kaggle test results and submit the results You will need to do a bit more setup for this. First, you need to get the Kaggle test images for classification. There are 12500 of these in the test.zip file from the site. Under the data directory, create a new directory called kaggle-test. Now unzip the contents of test.zip inside that folder. The full directory with all the test images should now be:\ndata/kaggle-test/test\nThis step takes a long time and you might have to tweak the batch size again depending on your memory. There are 12500 predications to be made. The main logic for this is in function called (kaggle-results batch-size). It will take a long time to run. It will print the results as it goes along to the kaggle-results.csv file. If you want to check progress you can do wc -l kaggle-results.csv\nFor me locally, with (cats-dogs/kaggle-results 100) it took me 28 minutes locally.\nCompare the results My one epoch of fine tuning beat my best results of going through the Practical Deep Learning exercise with the fine tuning the VGG16 model. Not bad at all.\nSummary For those of you that are interested in checking out the code, it\u0026rsquo;s out there on github\nEven more exciting, there is a walkthrough in a jupyter notebook with a lein-jupyter plugin.\nThe Deep Learning world in Clojure is an exciting place to be and gaining tools and traction more and more.\n","permalink":"https://gigasquidsoftware.com/blog/2017/11/07/cats-and-dogs-with-cortex-redux/","summary":"\u003cp\u003eI wrote a \u003ca href=\"http://gigasquidsoftware.com/blog/2016/12/27/deep-learning-in-clojure-with-cortex/\"\u003eblog post\u003c/a\u003e a while back about using a Clojure machine learning library called \u003ca href=\"https://github.com/thinktopic/cortex\"\u003eCortex\u003c/a\u003e to do the Kaggle Cats and Dogs classification challenge.\u003c/p\u003e\n\u003cp\u003eI wanted to revisit it for a few reasons. The first one is that the Cortex library has progressed and improved considerably over the last year. It\u0026rsquo;s still not at version 1.0, but it my eyes, it\u0026rsquo;s really starting to shine. The second reason is that they recently published an \u003ca href=\"https://github.com/thinktopic/cortex/tree/master/examples/resnet-retrain\"\u003eexample\u003c/a\u003e of using the RESNET50 model, (I\u0026rsquo;ll explain later on), to do fine-tuning or transfer learning. The third reason, is that there is a great new plugin for leiningen the supports using \u003ca href=\"https://github.com/didiercrunch/lein-jupyter\"\u003eJupyter notebooks with Clojure projects\u003c/a\u003e. These notebooks are a great way of doing walkthroughs and tutorials.\u003c/p\u003e","title":"Cats and Dogs with Cortex Redux"},{"content":"\nIn my talk at Clojure Conj I mentioned how a project from Oracle Labs named GraalVM might have to potential for Clojure to interop with Python on the same VM. At the time of the talk, I had just learned about it so I didn\u0026rsquo;t have time to take a look at it. Over the last week, I\u0026rsquo;ve managed to take it for a test drive and I wanted to share what I found.\nAre you ready? In this example, we will be using an ordinary Leinengen project and using the REPL we will interop with both R and python.\nBut first will need a bit of setup.\nWe will download the Graal project so we can use its java instead of our own.\nOnce we have it downloaded we will configure our PATH to use Graal\u0026rsquo;s java instead of our own.\n# export PATH=/path/to/graalAndTruffle/bin:$PATH Now, we can create a new lein project and run lein repl and begin the fun.\nThe Polyglot Context In our new namespace, we just need to import the Polyglot Context to get started:\n(ns graal-test.core (:import (org.graalvm.polyglot Context))) ;; note that is also supports Ruby, LLVM, and JS (def context (Context/create (into-array [\u0026#34;python\u0026#34; \u0026#34;R\u0026#34;]))) Now, we are ready to actually try to run some R and Python code right in our REPL. Let\u0026rsquo;s start first with R.\nInteroping with R The main function we are going to use is the eval function in the context. Let\u0026rsquo;s start small with some basic math.\n(.eval context \u0026#34;R\u0026#34; \u0026#34; 3^2 + 2^2 \u0026#34;) ;=\u0026gt; #object[org.graalvm.polyglot.Value 0x7ff40e4d \u0026#34;13.0\u0026#34;] Wow! It actually did something. It returned something called a Polyglot Value with what looks like the right answer in it.\nEmboldened by our early success, let\u0026rsquo;s try something a little more complicated like calling a function.\n(def result1 (.eval context \u0026#34;R\u0026#34; \u0026#34; sum.of.squares \u0026lt;- function(x,y) { x^2 + y^2 } sum.of.squares(3,4) \u0026#34;)) ;=\u0026gt; #object[org.graalvm.polyglot.Value 0xc3edd92 \u0026#34;25.0\u0026#34;] Again, it looks like it worked. Let\u0026rsquo;s try to get the result back into Clojure as a value we can work with. We could ask the result what sort of type it is with\n(.isNumber result1) ;=\u0026gt; true but let\u0026rsquo;s just use clojure.edn to read the string and save some time.\n(defn -\u0026gt;clojure [polyglot-value] (-\u0026gt; polyglot-value (.toString) (clojure.edn/read-string))) (-\u0026gt;clojure result1) ;=\u0026gt; 25 It would be nice to have a easier way to export symbols and import symbols to and from the guest and host language. In fact, Graal provides a way to do this but to do this in Clojure, we would need something else called Truffle.\nTruffle is part of the Graal project and is a framework for implementing languages with the Graal compliler. There are quite a few languages implemented with the Truffle framework. R is one of them.\nMy understanding is that if Clojure was implemented as a truffle lang, then interop could be much more seamless like this example in Ruby\nBut let\u0026rsquo;s continue in our exploration. What about doing something more interesting, like importing a useful R library and using it. How about the numDeriv package that supports Accurate Numerical Derivatives?\nFirst we import the package using cran.\n(.eval context \u0026#34;R\u0026#34; \u0026#34; install.packages(\\\u0026#34;numDeriv\\\u0026#34;, repos = \\\u0026#34;http://cran.case.edu/\\\u0026#34;) \u0026#34;) If you are doing this at your REPL, you can will see lots of text going on in your lein repl process at this point. It\u0026rsquo;s going out and figuring out what deps you need and installing them in your /graalvm-0.28.2/jre/languages/R directory structure.\nAfter it is done, we can actually use it!\n(def result2 (.eval context \u0026#34;R\u0026#34; \u0026#34; library(numDeriv) grad(sin, (0:10)*2*pi/10) \u0026#34;)) result2 ;=\u0026gt; #object[org.graalvm.polyglot.Value 0x76765898 \u0026#34;c(1, ;0.809016994367249, 0.309016994372158, -0.309016994373567, ;-0.809016994368844, -0.999999999993381, -0.809016994370298, ;-0.309016994373312, 0.309016994372042, 0.809016994369185, ;0.999999999993381)\u0026#34;] This has a bit more interesting result as an array. But the Context has ways of dealing with it.\n(.hasArrayElements result2) ;=\u0026gt; true (.getArraySize result2) ;=\u0026gt; 11 (for [i (range 10)] (-\u0026gt; (.getArrayElement result2 i) (-\u0026gt;clojure))) ;=\u0026gt; (1.0 0.8090169943672489 0.3090169943721585 -0.3090169943735675 ;-0.8090169943688436 -0.9999999999933814 ; -0.8090169943702977 -0.3090169943733122 0.30901699437204233 ; 0.8090169943691851) So, we\u0026rsquo;ve showed basic interop with R - which is pretty neat. What about Python?\nInteroping with Python Truffle is scheduled to fully support Python in 2018, but there is already an early alpha version in the Graal download that we can play with.\n(.eval context \u0026#34;python\u0026#34; \u0026#34; import time; time.clock() \u0026#34;) ;=\u0026gt; #object[org.graalvm.polyglot.Value 0x4a6b3b70 \u0026#34;1.508202803249E9\u0026#34;] Neat!\nIt is still a long way for import numpy or import tensorflow but cPython compatibility is the goal. Although the c-extensions are the really tricky part.\nSo keep an eye on Graal and Truffle for the future and wish the Oracle Labs team the best on their mission to make the JVM Polyglot.\nFootnotes If you are interested in playing with the code. I have a github repo here graal-test. If you are interested in watching a video, I really liked this one. There are also some really nice examples of running in polyglot mode with R and Java and JS here https://github.com/graalvm/examples.\n","permalink":"https://gigasquidsoftware.com/blog/2017/10/22/embedded-interop-between-clojure-r-and-python-with-graalvm/","summary":"\u003cp\u003e\u003cimg loading=\"lazy\" src=\"https://images-na.ssl-images-amazon.com/images/M/MV5BOTViY2Y0ZGItMTg2OC00YzEzLWJhYjYtZjg4OTMyOWE4YzM1XkEyXkFqcGdeQXVyNTQ1NzU4Njk@._V1_.jpg\"\u003e\u003c/p\u003e\n\u003cp\u003eIn my talk at \u003ca href=\"https://www.youtube.com/watch?v=eLl6_k_fZn4\"\u003eClojure Conj\u003c/a\u003e I mentioned how a project from Oracle Labs named GraalVM might have to potential for Clojure to interop with Python on the same VM. At the time of the talk, I had just learned about it so I didn\u0026rsquo;t have time to take a look at it. Over the last week, I\u0026rsquo;ve managed to take it for a test drive and I wanted to share what I found.\u003c/p\u003e","title":"Embedded Interop between Clojure, R, and Python with GraalVM"},{"content":"So, you have an idea for a fiction book. First, let me tell you that it\u0026rsquo;s a good idea and it\u0026rsquo;s a great thing that you are a coder. Quite a few successful authors have a background in software development. Arrival, (which is a fabulous movie), comes from the book, Stories of your Life, written by a fellow programmer Ted Chiang. Charlie Stross is another fine example. One of my favorites is [Daniel Suarez](https://en.wikipedia.org/wiki/Daniel_Suarez_(author), the author of the Daemon and more recently Change Agent. So yes, you can write a fiction book and you\u0026rsquo;re in good company. This post is dedicated to help make it happen.\nSo how do you know about self publishing? Two years ago, I had a semi-crazy idea for a tween/teen scifi book. At the time, my daughter was into all the popular books of time like Hunger Games and Divergent. The thing that I really liked about them was the strong female protagonist. The only thing that I thought was missing was a story that focused on a girl who could code. It would make it even better if she had coding super powers. The idea for Code Shifter was born. One of the things that I wanted to explore in writing the book was to have real programming code in the book but not have it be a learning how to code book. The code would exist as part of the story and if the reader picked up concepts along the way, great. Even if they didn\u0026rsquo;t, it would lay the positive groundwork to have them be more open to it later.\nBooks, like software, always take longer than you plan. My daughter and I enjoyed working on it together and over time it grew into a book that we could share with others. Along the way, I learned quite a bit about writing books, publishing, and other things that I wish I had known beforehand.\nWhat did you use to write the book? In the book world, your story is referred to as your manuscript. As a tool to produce it, I cannot speak highly enough of Leanpub. I found it easy and productive to work in as a programmer. For example, my setup was pretty painless.\nIn the repo, I had a manuscript directory, in which there was a Book.txt file that listed the chapter files.\nchapter2.txt chapter3.txt chapter4.txt chapter5.txt Each chapter file in turn was written in markdown. For example, chapter2.txt looked like this:\n# 1 ## Flicker Twelve-year-old Eliza knew that the next words were the result of computer program far more intelligent than any one of them. Standing next to her parents, she held her breath and watched as her brother touched his finger to the message on the wall screen. From there, my process looked like:\nWrite a bit in my favorite editor, (Emacs of course), and make a commit. Push the commit to github, which is registered with the Leanpub project Log onto the Leanpub project and hit the preview button. This would generate a pdf and ebook that I could share with my daughter for feedback. Advantages of Leanpub for development. As I said earlier, I\u0026rsquo;m a fan. Using git for revisions is incredibly useful. I shudder to think of people writing in Word without version control. The ability to easily create PDF and ebook formats was also very convenient. The markdown format has excellent code support. There is also the option as publishing your work as you go. However, I think that this is more useful with a technical book than with fiction.\nDisadvantages of Leanpub for development If you are going to work with an freelance editor or share your work with someone in the mainstream book world, they are not going to want pdf. They usually want a doc version. It took me a bit of research to find a good converter, pandoc. With it, you can convert from markdown to Word with things looking pretty good. Don\u0026rsquo;t try to do pdf to Word. I found it a big recipe for fail.\nFinally, the book was considered done enough to think about publishing.\nThere was much rejoicing.\nDidn\u0026rsquo;t you want to get the book into bookstores? Of course. That would be incredibly cool. However, that requires getting into what they call traditional publishing and it is a lot more work, time, and luck. If you go this route, you will need to budget at least six months to send out form letters to agencies to have them represent your work. Also, beware of predatory services that take advantage of unsuspecting and wide eyed authors. If you are interested in this, you\u0026rsquo;ll want to start looking for agents that are interested in your type of book. Query Tracker is a great place to start.\nTraditional publishing sounds hard. What about self publishing? Self publishing is certainly an easier more direct way to bring your book to life. For me, it was the best way forward. Luckily, Leanpub made it pretty painless.\nPublishing the book with Leanpub Actually publishing the finished copy was really easy with Leanpub. All I had to do was fill in some fields on the project page and push Publish! The book was immediately ready to share with the world. Putting out an updated edition was as easy as pushing the button again. Leanpub provides online reading as well as all the ebook versions.\nThat was nice, but I really wanted a print copy too.\nPublishing with CreateSpace Amazon\u0026rsquo;s CreateSpace provides and excellent platform for on-demand print copies of books. This is where Leanpub comes in handy again. There is an Export Option that provides and unbranded pdf copy of your manuscript with all the correct formatting and margins required for CreateSpace. I simply exported the file and then uploaded it up to the project.\nThe other thing that you will want is a nice cover. There are services through CreateSpace for cover creation that you can buy or you can upload your own file. I was lucky enough to have a talented graphic designer as sister, Kristin Allmyer, who made me an awesome cover.\nOne of the confusing things was picking an ISBN for the print copy. You don\u0026rsquo;t need to worry about this for ebook versions but you do for a physical copy. Your choices through CreateSpace are using a provided one for free or buying your own for $99. I chose my own so I could have flexibility of working with another publisher other than Amazon if I want. If you choose that option, you can also make up your own publisher name. Mine is Gigasquid Books.\nOnce you have completed all the setup, they will send you a physical copy in the mail to approve. The moment you get to hold it in your hands is really magical.\nIf it looks alright, you hit the approve button and voilà - it\u0026rsquo;s for sale on Amazon!\nPublishing with Direct Kindle Publishing With CreateSpace, you have the option of porting your book to a Kindle format as well. It will do most of the heavy lifting of converting the files for you and a few button clicks later you have both an Kindle and print version available for your readers.\nIf you need to update the text of the Kindle version, Leanpub also has an export option available to produce unbranded ebook files. Just take this and upload it to your KDP account and you are good to go.\nDid you run into any problems? Of course I did. I was totally new to self publishing and I underestimated how hard copy editing is. Some errors unfortunately made it into the first version. Luckily, I had some really nice people that helped my fix it for later versions. Many thanks to Martin Plumb, Michael Daines, Paul Henrich, and S. Le Callonnec for editing help.\nThis brings me to my next point. If I had to do it all over again, I would publish the book in a different order. Books are really no different than software. There are going to be bugs when you first release it in the wild. It is best to embrace this. In the future, I would publish the ebook versions first, which are much easier to update and then the print versions after that.\nDid you make lots of money from the book sales? Hahaha \u0026hellip; that\u0026rsquo;s funny. If you are interested in making money, books are not the best way to go. The margins on Leanpub are definitely better than Amazon, but if I really was interested in making money, I would have been much better off using deep learning to make a stock market predictor or code up a startup that I could sell off.\nAuthors in general, are much harder pressed to make livings than software developers. We should count our blessings.\nAny last words of advice? There is a great joy from creating a story and sharing it with others. Take your book idea, nurture it, and bring it to life. Then publish it and we can celebrate together.\n","permalink":"https://gigasquidsoftware.com/blog/2017/05/27/self-publishing-for-the-creative-coder/","summary":"\u003cp\u003eSo, you have an idea for a fiction book. First, let me tell you that it\u0026rsquo;s a good idea and it\u0026rsquo;s a great thing that you are a coder. Quite a few successful authors have a background in software development. \u003ca href=\"http://www.imdb.com/title/tt2543164/\"\u003eArrival\u003c/a\u003e, (which is a fabulous movie), comes from the book, \u003ca href=\"https://www.amazon.com/Stories-Your-Life-Others-Chiang/dp/1101972122\"\u003eStories of your Life\u003c/a\u003e,  written by a fellow programmer \u003ca href=\"https://en.wikipedia.org/wiki/Ted_Chiang\"\u003eTed Chiang\u003c/a\u003e. \u003ca href=\"https://en.wikipedia.org/wiki/Charles_Stross\"\u003eCharlie Stross\u003c/a\u003e is another fine example. One of my favorites is [Daniel Suarez](\u003ca href=\"https://en.wikipedia.org/wiki/Daniel_Suarez_(author)\"\u003ehttps://en.wikipedia.org/wiki/Daniel_Suarez_(author)\u003c/a\u003e, the author of the\u003ca href=\"https://www.amazon.com/DAEMON-Daniel-Suarez/dp/0451228731\"\u003e Daemon\u003c/a\u003e and more recently \u003ca href=\"https://www.amazon.com/Change-Agent-Novel-Daniel-Suarez/dp/110198466X/\"\u003eChange Agent\u003c/a\u003e. So yes, you can write a fiction book and you\u0026rsquo;re in good company. This post is dedicated to help make it happen.\u003c/p\u003e","title":"Self Publishing for the Creative Coder"},{"content":"Update: Cortex has moved along since I first wrote this blog post, so if you are looking to run the examples, please go and clone the Cortex repo and look for the cats and dogs code in the examples directory.\nThere is an awesome new Clojure-first machine learning library called Cortex that was open sourced recently. I\u0026rsquo;ve been exploring it lately and wanted to share my discoveries so far in this post. In our exploration, we are going to tackle one of the classic classification problems of the internet. How do you tell the difference between a cat and dog pic?\nWhere to Start? For any machine learning problem, we\u0026rsquo;re going to need data. For this, we can use Kaggle\u0026rsquo;s data for the Cats vs Dogs Challenge. The training data consists of 25,000 images of cats and dogs. That should be more than enough to train our computer to recognize cats from doggies.\nWe also need some idea of how to train against the data. Luckily, the Cortex project has a very nice set of examples to help you get started. In particular there is a suite classification example using MNIST, (hand written digit), corpus. This example contains a number cutting edge features that we\u0026rsquo;ll want to use:\nUses GPU for fast computation. Uses a deep, multi-layered, convolutional layered network for feature recognition. Has \u0026ldquo;forever\u0026rdquo; training by image augmentation. Saves the network configuration as it trains to an external nippy file so that it can be imported later. Has a really nice ClojureScript front end to visualize the training progress with a confusion matrix. Has a way to import the saved nippy network configuration and perform inference on it to classify a new image. Basically, it has everything we need to hit the ground running.\nData Wrangling To use the example\u0026rsquo;s forever training, we need to get the data in the right form. We need all the images to be the same size as well as in a directory structure that is split up into the training and test images. Furthermore, we want all the dog images to be under a \u0026ldquo;dog\u0026rdquo; directory and the cat images under the \u0026ldquo;cat\u0026rdquo; directory so that the all the indexed images under them have the correct \u0026ldquo;label\u0026rdquo;. It will look like this:\n- training - cat - 1.png - 2.png - dog - 1.png - 2.png For this task, we are going to use a couple image libraries to help us out:\n[mikera.image.core :as imagez] [think.image.image :as image] We can resize and rewrite the original images into the form we want. For a image size, we\u0026rsquo;re going to go with 52x52. The choice is arbitrary in that I wanted it bigger than the MNIST dataset which is 28x28 so it will be easier to see, but not so big that it kills my CPU. This is even more important since we want to use RGB colors which is 3 channels as opposed to the MNIST grey scale of 1.\n(def dataset-image-size 52) (def dataset-num-classes 2) (def dataset-num-channels 3) (def dataset-datatype :float) (defn resize-and-write-data [output-dir [idx [file label]]] (let [img-path (str output-dir \u0026#34;/\u0026#34; label \u0026#34;/\u0026#34; idx \u0026#34;.png\u0026#34; )] (when-not (.exists (io/file img-path)) (io/make-parents img-path) (-\u0026gt; (imagez/load-image file) (image/resize dataset-image-size dataset-image-size) (imagez/save img-path))) nil)) As far as the split between training images and testing images, we are going the go for an simple even split between testing and training data.\nNetwork Configuration The Network layer configuration is the meat of the whole thing. We are going to go with the exact same network description as the MNIST example:\n(defn create-basic-network-description [] [(desc/input dataset-image-size dataset-image-size dataset-num-channels) (desc/convolutional 5 0 1 20) (desc/max-pooling 2 0 2) (desc/relu) (desc/convolutional 5 0 1 50) (desc/max-pooling 2 0 2) (desc/relu) (desc/convolutional 1 0 1 50) (desc/relu) (desc/linear-\u0026gt;relu 1000) (desc/dropout 0.5) (desc/linear-\u0026gt;softmax dataset-num-classes)]) It uses a series of convolutional layers with max pooling for feature recognition. We\u0026rsquo;ll see if it works for color versions of cats and dogs as well as street numbers.\nWe\u0026rsquo;ll also keep the image augmentation the same as in the example.\n(def max-image-rotation-degrees 25) (defn img-aug-pipeline [img] (-\u0026gt; img (image-aug/rotate (- (rand-int (* 2 max-image-rotation-degrees)) max-image-rotation-degrees) false) (image-aug/inject-noise (* 0.25 (rand))))) (def ^:dynamic *num-augmented-images-per-file* 1) It injects one augmented image into our training data by slightly rotating it and adding noise.\nRunning it! It\u0026rsquo;s time to test it out. Using lein run, we\u0026rsquo;ll launch the train-forever function:\n(defn train-forever [] (let [dataset (create-dataset) initial-description (create-basic-network-description) confusion-matrix-atom (display-dataset-and-model dataset initial-description)] (classification/train-forever dataset observation-\u0026gt;image initial-description :confusion-matrix-atom confusion-matrix-atom))) This opens a port to a localhost webpage where we can view the progress http://localhost:8091/\nBelow the confusion matrix is shown. This tracks the progress of the training in the classification. In particular, how many times it thought a cat was really a cat and how many times it got it wrong.\nAs we are training the data, the loss for each epoch is shown on the console as well as when it saves the network to the external file.\nAfter only thirty minutes of training on my Mac Book Pro, we get to some pretty good results, with the correct percentage in the 99s :\nIt\u0026rsquo;s time to do some inference on our trained network.\nInference Firing up a REPL we can connect to our namespace and use the label-one function from the cortex example to spot check our classification. It reads in the external nippy file that contains the trained network description, takes a random image from the testing directory, and classifies it.\n(defn label-one \u0026#34;Take an arbitrary image and label it.\u0026#34; [] (let [file-label-pairs (shuffle (classification/directory-\u0026gt;file-label-seq testing-dir false)) [test-file test-label] (first file-label-pairs) test-img (imagez/load-image test-file) observation (png-\u0026gt;observation dataset-datatype false test-img)] (imagez/show test-img) (infer/classify-one-observation (:network-description (suite-io/read-nippy-file \u0026#34;trained-network.nippy\u0026#34;)) observation (ds/create-image-shape dataset-num-channels dataset-image-size dataset-image-size) dataset-datatype (classification/get-class-names-from-directory testing-dir)))) Running (label-one) gives us the picture:\nand classifies it as a cat. Yipee!\n{:probability-map {\u0026#34;cat\u0026#34; 0.9995587468147278, \u0026#34;dog\u0026#34; 4.4119369704276323E-4}, :classification \u0026#34;cat\u0026#34;} Not bad, but let\u0026rsquo;s try it with something harder. Personally, I\u0026rsquo;m not even sure whether this is a cat or a dog.\nFeeding it through the program - it says it is a cat.\n{:probability-map {\u0026#34;cat\u0026#34; 0.9942012429237366, \u0026#34;dog\u0026#34; 0.005798777565360069}, :classification \u0026#34;cat\u0026#34;} After much debate on the internet, I think that is the best answer the humans got too :)\nKaggle it So it seems like we have a pretty good model, why don\u0026rsquo;t we submit our results to the Kaggle competition and see how it rates. All they need is to have us run the classification against their test data of 12,500 images and classify them as 1 = dog or 0 = cat in a csv format.\nWe will take each image and resize it, then feed it into cortex\u0026rsquo;s infer-n-observations function, to do all our classification as a batch.\n(infer/infer-n-observations (:network-description (suite-io/read-nippy-file \u0026#34;trained-network.nippy\u0026#34;)) observations (ds/create-image-shape dataset-num-channels dataset-image-size dataset-image-size) dataset-datatype) Finally, we just need to format our results to a csv file and export it:\n(defn write-kaggle-results [results] (with-open [out-file (io/writer \u0026#34;kaggle-results.csv\u0026#34;)] (csv/write-csv out-file (into [[\u0026#34;id\u0026#34; \u0026#34;label\u0026#34;]] (-\u0026gt; (mapv (fn [[id class]] [(Integer/parseInt id) (if (= \u0026#34;dog\u0026#34; class) 1 0)]) results) (sort)))))) After uploading the file to the Kaggle, I was pleased that the answer got in the top 91%! It made it on the Leaderboard.\nConclusion Using an example setup from the Cortex project and 30 minutes of processing time on my laptop, we were able to crunch through some significant data and come up with a trained classification model that was good enough to make the charts in the Kaggle competition. On top of it all, it is in pure Clojure.\nIn my mind, this is truely impressive and even though the Cortex library is in it\u0026rsquo;s early phases, it puts it on track to be as useful a tool as Tensor Flow for Machine Learning.\nEarlier this month, I watched an ACM Learning webcast with Peter Norvig speaking on AI. In it, he spoke of one of the next challenges of AI which is to combine symbolic with neural. I can think of no better language than Clojure with it\u0026rsquo;s simplicity, power, and rich LISP heritage to take on the challenge for the future. With the Cortex library, it\u0026rsquo;s off to a great start.\nIf want to see all the cats vs dog Kaggle Code, it\u0026rsquo;s out on github here https://github.com/gigasquid/kaggle-cats-dogs\n","permalink":"https://gigasquidsoftware.com/blog/2016/12/27/deep-learning-in-clojure-with-cortex/","summary":"\u003cp\u003e\u003cstrong\u003eUpdate: Cortex has moved along since I first wrote this blog post, so if you are looking to run the examples, please go and clone the \u003ca href=\"https://github.com/thinktopic/cortex\"\u003eCortex\u003c/a\u003e repo and look for the cats and dogs code in the examples directory.\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003eThere is an awesome new \u003cem\u003eClojure-first\u003c/em\u003e machine learning library called \u003ca href=\"https://github.com/thinktopic/cortex\"\u003eCortex\u003c/a\u003e that was open sourced recently. I\u0026rsquo;ve been exploring it lately and wanted to share my discoveries so far in this post. In our exploration, we are going to tackle one of the classic classification problems of the internet. How do you tell the difference between a cat and dog pic?\u003c/p\u003e","title":"Deep Learning in Clojure with Cortex"},{"content":"\nClojure.spec is a new library for Clojure that enables you to write specifications for your program. In an earlier post, I showed off some of it\u0026rsquo;s power to generate test data from your specifications. It\u0026rsquo;s a pretty cool feature. Given some clojure.spec code, you can generate sample data for you based off of the specifications. But what if you could write a program that would generate your clojure.spec program based off of data so that you could generate more test data?\nGenetic programming Here is where we embark for fun. We are going to use genetic programming to generate clojure.spec creatures that contain a program. Through successive generations, those creatures will breed, mutate, and evolve to fit the data that we are going to give it. Going with our creature theme, we can say that it eats a sequence of data like this\n[\u0026#34;hi\u0026#34; true 5 10 \u0026#34;boo\u0026#34;] Each creature will be represented by a map that has information about two key pieces, its program and the fitness score. Each program is going to start with a clojure.spec/cat, (which is the spec to describe a sequence). From here on out, I\u0026rsquo;m going to refer to the clojure.spec namespace as s/. So, a simple creature would look like this.\n{:program (s/cat :0 int? :1 string?) :score 0} How do we figure out a score from the creature\u0026rsquo;s spec? We run the spec and see how much of the data that it can successfully consume.\nScoring a creature To score a creature, we\u0026rsquo;re going to use the clojure.spec explain-data function. It enables us to run a spec against some data and get back the problems in a data format that we can inspect. If there are no problems and the spec passes, the result is nil.\n(s/explain-data (s/cat :0 int? :1 string?) [1 \u0026#34;hi\u0026#34;]) ;=\u0026gt; nil However, if there is a problem, we can get information about what went wrong. In particular, we can see where it went wrong in the sequence.\n(s/explain-data (s/cat :0 int? :1 string?) [1 true]) ;=\u0026gt; #:clojure.spec{:problems [{:path [:1], :pred string?, :val true, :via [], :in [1]}]} In the above example, the :in key tells us that it fails at index 1. This gives us all the information we need to write a score function for our creature.\n(defn score [creature test-data] (try (let [problems (:clojure.spec/problems (s/explain-data (eval (:program creature)) test-data))] (if problems (assoc creature :score (get-in problems [0 :in 0])) (assoc creature :score 100))) (catch Throwable e (assoc creature :score 0)))) This function tries to run the spec against the data. If there are no problems, the creature gets a 100 score. Otherwise, it records the farthest point in the sequence that it got. Creatures with a higher score are considered more fit.\n(score {:program \u0026#39;(s/cat :0 int? :1 string?)} [1 true]) ;=\u0026gt; {:program (s/cat :0 int? :1 string?), :score 1} Now that we have a fitness function to evaluate our creatures, we need a way to generate a random clojure.spec creature.\nCreate a random creature This is where I really love Clojure. Code is data, so we can create the programs as lists and they are just themselves. To run the programs, we just need to call eval on them. We are going to constrain the creatures somewhat. They are all going to start out with s/cat and have a certain length of items in the sequence. Also, we are going to allow the parts of the spec to be created with certain predicates.\n(def preds [\u0026#39;integer? \u0026#39;string? \u0026#39;boolean? \u0026#39;(s/and integer? even?) \u0026#39;(s/and integer? odd?)]) Also allowing, composition with ands and ors and other sequences.\n(def seqs [\u0026#39;s/+ \u0026#39;s/*]) (def and-ors [\u0026#39;s/and \u0026#39;s/or]) We are also going to have some probability knobs to control how the random creature is constructed.\n(def seq-prob 0.3) (def nest-prob 0.00) (def max-depth 4) (def and-or-prob 0.85) The seq-prob is the probability that a new spec sub sequence will be constructed. The nest-prob is set to zero right now, to keep things simple, but if turned up with increase the chance that a nested spec sequence would occur. We are going to be writing a recursive function for generation, so we\u0026rsquo;ll keep things to a limited depth with max-depth. Finally, we have the chance that when constructing a spec sub sequence, that it will be an and/or with and-or-prob. Putting it all together with code to construct a random arg.\n(defn make-random-arg [n] (if (and (pos? n) (\u0026lt; (rand) seq-prob)) (make-random-seq n) (rand-nth preds))) Also creating a random sub sequence.\n(defn make-random-seq [n] (cond (\u0026lt; (rand) nest-prob) `(s/spec (~(rand-nth seqs) ~(make-random-arg (dec n)))) (\u0026lt; (rand) and-or-prob) `(~(rand-nth and-ors) ~(make-random-arg (dec n)) ~(make-random-arg (dec n))) :else `(~(rand-nth seqs) ~(make-random-arg (dec n))))) Finally, we can create a random s/cat spec with\n(defn make-random-cat [len] (let [args (reduce (fn [r i] (conj r (keyword (str i)) (make-random-arg max-depth))) [] (range len))] `(s/cat ~@args))) Let\u0026rsquo;s see it in action.\n(make-random-cat 3) ;=\u0026gt; (clojure.spec/cat :0 (s/and integer? odd?) :1 integer? :2 boolean?) We can make a batch of new creatures for our initial population using this function.\n(defn initial-population [popsize max-cat-length] (for [i (range popsize)] {:program (make-random-cat (inc (rand-int max-cat-length)))})) Great! Now we have a way to make new random spec creatures. But, we need a way to alter them and let them evolve. The first way to do this is with mutation.\nMutating a creature Mutation in our case, means changing part of the code tree of the creature\u0026rsquo;s program. To keep the program runnable, we don\u0026rsquo;t want to be able to mutate every node, only specific ones. We\u0026rsquo;re going to control this by defining a mutable function that will only change nodes that start with our sequences or predicates.\n(defn mutable? [node] (or (when (seq? node) (contains? (set/union (set seqs) #{\u0026#39;clojure.spec/spec}) (first node))) (contains? (set preds) node))) Then, we can use postwalk to walk the code tree and alter a node by a mutation probability factor\n(def mutate-prob 0.1) (defn mutate [creature] (let [program (:program creature) mutated-program (walk/postwalk (fn [x] (if (and (mutable? x) (\u0026lt; (rand) mutate-prob)) (make-random-arg max-depth) x)) program)] (assoc creature :program mutated-program))) Trying it on one of our creatures.\n(mutate {:program \u0026#39;(clojure.spec/cat :0 (s/and integer? odd?) :1 integer?)}) ;=\u0026gt; {:program (clojure.spec/cat :0 (s/or (s/and integer? even?)) :1 integer?)} We can change our creatures via mutation, but what about breeding it with other creatures?\nCrossovers with creatures Crossover is another way to modify programs. It takes two creatures and swaps a node from one creature to another. To accomplish this, we\u0026rsquo;re going to use the walk function to select at a random probability the crossover node from the first node, then insert it into the second\u0026rsquo;s creatures program at another random spot.\n(def crossover-prob 0.7) (defn crossover [creature1 creature2] (let [program1 (:program creature1) program2 (:program creature2) chosen-node (first (walk/walk #(when (and (\u0026lt; (rand) crossover-prob) (mutable? %)) %) #(remove nil? %) program1)) crossed-over? (atom false) crossover-program (if chosen-node (walk/postwalk (fn [x] (if (and (mutable? x) (\u0026lt; (rand) crossover-prob) (not @crossed-over?)) (do (reset! crossed-over? true) chosen-node) x)) program2) program2)] {:program crossover-program})) Taking two creatures and putting them together.\n(crossover {:program \u0026#39;(clojure.spec/cat :0 (s/and integer? odd?) :1 integer?)} {:program \u0026#39;(clojure.spec/cat :0 string? :1 boolean?)}) ;=\u0026gt; {:program (clojure.spec/cat :0 (s/and integer? odd?) :1 boolean?)} We have our ways to change our creatures to let them evolve and we have a way to rank them. What we need now is to put it together in a way that will let them evolve to the solution.\nEvolving creatures The process will be in general terms:\nCreate initial population Rank them Take the top two best ones and carry them over (this is known as elitism) Create the next generation from by selecting creatures for crossover and mutation Repeat! So how do we select the best creatures for our next population? This is an interesting question, there are many approaches. The one that we\u0026rsquo;re going to use is called tournament selection. It involves picking n creatures from the whole population and then, among those, picking the best scored one. This will allow diversity in our population that is needed for proper evolution.\n(defn select-best [creatures tournament-size] (let [selected (repeatedly tournament-size #(rand-nth creatures))] (-\u0026gt; (sort-by :score selected) reverse first))) We\u0026rsquo;re now ready to write our evolve function. In it, we pass in the population size, how many generations we want, the tournament size, and of course, our test data that our creatures are going to feed on. The loop ends when it reaches a perfect fitting solution, (a creature with a score of 100), or the max generations.\nNote that we have a chance for a completely random creature to appear in the generations, to further encourage diversity.\n(defn perfect-fit [creatures] (first (filter #(= 100 (:score %)) creatures))) (defn evolve [pop-size max-gen tournament-size test-data] (loop [n max-gen creatures (initial-population pop-size (count test-data))] (println \u0026#34;generation \u0026#34; (- max-gen n)) (let [scored-creatures (map (fn [creature] (score creature test-data)) creatures)] (if (or (zero? n) (perfect-fit scored-creatures)) scored-creatures (let [elites (take 2 (reverse (sort-by :score scored-creatures))) new-creatures (for [i (range (- (count creatures) 2))] ;; add a random node to improve diversity (if (\u0026lt; (rand) new-node-prob) {:program (make-random-cat (count test-data))} (let [creature1 (select-best scored-creatures tournament-size) creature2 (select-best scored-creatures tournament-size)] (mutate (crossover creature1 creature2)))))] (println \u0026#34;best-scores\u0026#34; (map :score elites)) (recur (dec n) (into new-creatures elites))))))) Trying it out. We get a perfect clojure.spec creature!\n(def creature-specs (evolve 100 100 7 [\u0026#34;hi\u0026#34; true 5 10 \u0026#34;boo\u0026#34;])) (perfect-fit creature-specs) ;=\u0026gt;{:program (clojure.spec/cat :0 string? :1 boolean? :2 (s/and integer? odd?) :3 integer? :4 string?) :score 100} Of course, our clojure.spec creature can generate data on its own with the exercise function. Let\u0026rsquo;s have it generate 5 more examples of data that conform to its spec.\n(s/exercise (eval (:program (perfect-fit creature-specs))) 5) ;; ([(\u0026#34;\u0026#34; true -1 -1 \u0026#34;\u0026#34;) {:0 \u0026#34;\u0026#34;, :1 true, :2 -1, :3 -1, :4 \u0026#34;\u0026#34;}] ;; [(\u0026#34;D\u0026#34; false -1 -1 \u0026#34;G\u0026#34;) {:0 \u0026#34;D\u0026#34;, :1 false, :2 -1, :3 -1, :4 \u0026#34;G\u0026#34;}] ;; [(\u0026#34;12\u0026#34; false -1 0 \u0026#34;l0\u0026#34;) {:0 \u0026#34;12\u0026#34;, :1 false, :2 -1, :3 0, :4 \u0026#34;l0\u0026#34;}] ;; [(\u0026#34;\u0026#34; false -1 -2 \u0026#34;\u0026#34;) {:0 \u0026#34;\u0026#34;, :1 false, :2 -1, :3 -2, :4 \u0026#34;\u0026#34;}] ;; [(\u0026#34;2\u0026#34; false 1 0 \u0026#34;Jro\u0026#34;) {:0 \u0026#34;2\u0026#34;, :1 false, :2 1, :3 0, :4 \u0026#34;Jro\u0026#34;}]) If we wanted to, we could adjust our evolve function and let it continue to evolve creatures and lots of different solutions to choose from. We could even take the generated data from the exercise function and let it generate more creatures who generate more data\u0026hellip;\u0026hellip;\nThe mind boggles.\nWe\u0026rsquo;ll leave with a quick summary of Genetic Programming.\nStart with a way to generate random creatures Have a way to evaluate their fitness Create a way to change them for the next generations using Mutation Crossover Have an evolution process Create an initial population Rank them Create the next generation using selection techniques and mutation/ crossovers Don\u0026rsquo;t forget about diversity Most importantly, have fun!\nIf you want to play with the code, it\u0026rsquo;s on github here https://github.com/gigasquid/genetic-programming-spec\nIf you want to learn more about clojure.spec this video is a great place to start. The guide is also a great reference with examples.\nIf you want to learn more about genetic programming, there are a couple of books I would recommend: Collective Intelligence and Genetic Algorithms + Data Structures = Evolution Programs\n","permalink":"https://gigasquidsoftware.com/blog/2016/07/18/genetic-programming-with-clojure.spec/","summary":"\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/images/posts/61dafbcb-28320682816_44780d1b75.jpg\"\u003e\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://blog.cognitect.com/blog/2016/5/23/introducing-clojurespec\"\u003eClojure.spec\u003c/a\u003e is a new library for Clojure that enables you to write specifications for your program.  In an earlier \u003ca href=\"http://gigasquidsoftware.com/blog/2016/05/29/one-fish-spec-fish/\"\u003epost\u003c/a\u003e, I showed off some of it\u0026rsquo;s power to generate test data from your specifications.  It\u0026rsquo;s a pretty cool feature.  Given some clojure.spec code, you can generate sample data for you based off of the specifications.  But what if you could write a program that would \u003cem\u003egenerate\u003c/em\u003e your clojure.spec program based off of data so that you could generate more test data?\u003c/p\u003e","title":"Genetic Programming with clojure.spec"},{"content":"I sit next to my daughter, showing her programming for the first time.\n(+ 1 1) \u0026ldquo;Now press enter.\u0026rdquo;\n2 \u0026ldquo;Pretty cool, huh?\u0026rdquo;\nShe looks unimpressed. I fear I\u0026rsquo;m losing her. How can I explain that this is just a small tip of something so much bigger?\nYou can make the code sing to you. You can take these numbers, turn them into notes, and line them up with the beat of your heart. Bring in the melody and chorus and build them up to a crescendo. Let it crash in waves and then\nYou can make the code dance for you. You can create delicate swirls and patterns with mathematical expressions. Have them pulse to the music in a never ending prism of fractals, flexing your control with confidence because\nYou can make the code lift you up. It doesn\u0026rsquo;t matter if you don\u0026rsquo;t look like them. It doesn\u0026rsquo;t matter if they think you don\u0026rsquo;t belong. They can\u0026rsquo;t hold you back. You\u0026rsquo;re smart and strong and\nYou can make the code create your life. You can solve problems for people. Make things work better and faster. Keep the data flowing. Make a company for yourself. Watch that company and your power and influence in the world grow until nothing feels out of reach and then, if you\u0026rsquo;re not careful\nYou can make the code hard and cruel. You can automate hate. Use the latest AI to keep them in control. Watch them with never sleeping eyes. Steal their money and point guns at them with armed robots. Then, late at night, you can think how\nYou can let the code control you. You can forget the important things in life. Turn away from family and friends. Lose yourself in some self created digital representation of yourself that never feels smart enough and leaves you grasping for more. Until that day, when you walk the streets with a deadened heart and you see the sad faces all around and you remember that\nYou can let the code make them smile. You can use your skills to brighten dark days. Use your programs to make them laugh. When you have their attention, inspire them to dream with you of a better world and next\nYou can make the code save lives. You can turn those algorithms to heal. Dive in and join the battle against death and disease. Make sense of all the data. Then lift your head to the sky and\nYou can make the code reach the stars. You can see the surface of Mars. Pick up a rock from a planet that was unimaginable generations before. Look out at what is beyond our solar system and peer into the mysteries of the beginning of time.\nYou can. All these things are yours now. The terrible and beautiful power of it.\nI reach down to type the code that distills my hopes and fears for the next generation.\n(println \u0026#34;Hello World\u0026#34;) Then I slide the keyboard over to her, a tear sliding down my cheek, and lean over to whisper the only advice that I can form into words,\n\u0026ldquo;Don\u0026rsquo;t forget the closing parens.\u0026rdquo;\n","permalink":"https://gigasquidsoftware.com/blog/2016/07/03/hello-world-for-the-next-generation/","summary":"\u003cp\u003eI sit next to my daughter, showing her programming for the first time.\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-clojure\" data-lang=\"clojure\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e(+ \u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e\u0026ldquo;Now press enter.\u0026rdquo;\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-clojure\" data-lang=\"clojure\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ae81ff\"\u003e2\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e\u0026ldquo;Pretty cool, huh?\u0026rdquo;\u003c/p\u003e\n\u003cp\u003eShe looks unimpressed.  I fear I\u0026rsquo;m losing her.  How can I explain that this is just a small tip of something so much bigger?\u003c/p\u003e\n\u003ch3 id=\"you-can-make-the-code-sing-to-you\"\u003eYou can make the code sing to you.\u003c/h3\u003e\n\u003cp\u003eYou can take these numbers, turn them into notes, and line them up with the beat of your heart. Bring in the melody and chorus and build them up to a crescendo. Let it crash in waves and then\u003c/p\u003e","title":"Hello World for the Next Generation"},{"content":"\nSo you want to write a book? Awesome. I\u0026rsquo;ve been working on one too for the last year.\nNo, it\u0026rsquo;s not really a programming book, but it does have code in it. It\u0026rsquo;s a sci-fi/fantasy book written for my ten year daughter, but this post isn\u0026rsquo;t about that. It\u0026rsquo;s about sharing the tools and setup that I\u0026rsquo;ve found work best for me.\nTools for Writing If the first thing you think of when you want to write a book is creating some really cool tools to help you, I can totally relate. It\u0026rsquo;s a programmer thing.\nHold on though, there\u0026rsquo;s another way.\nStarting out with only my book idea, I spent some time looking at the best authoring tools out there. I knew that I wanted to able to write in an editor that I was comfortable in and in a terse format like Markdown. I also wanted to be able to use git for revision management. After searching, I settled on Leanpub\nLeanpub is a free service for authoring that has Git integration in Markdown format. With it, I was able to write in my favorite text editor, (Emacs of course), commit and push my changes to my git repo, and then generate PDF and e-book formats. The multiple formats were important to me because it allowed me to share my chapters and get feedback.\nTools for Feedback Since I was writing a book with my daughter in mind, the most important feedback was from her. After every chapter was done. I would either print her out a copy or download it to her Kindle for review. She actually really enjoyed reading it on her Kindle because it made it for more real to her. My son also got interested in the story and before long, I had them both getting in heated debates about which direction the story should go.\nAfter my kids reviewed the chapters, I also sought some professional writing advice from a free-lance editor. I highly recommend getting this sort of feedback from an editor, writing group, or trusted friend to help you grow and improve. The one catch is that most of the writing world works with Microsoft Word, so I needed to convert my chapters to that format.\nFrom my experience, all PDF to Word converters are full of fail. The formatting goes all over the place and your writing ends up looking like some horrible abstract text art experiment gone wrong. So far, the best converter I\u0026rsquo;ve found is pandoc. It allows you to take your Markdown files and turn them into quite presentable Word documents.\nIf you have a Mac, it\u0026rsquo;s as simple as brew install pandoc. Then, you can create a simple script to convert all your chapters,(or a selection) into a properly formatted Word Doc.\n#!/bin/bash rm ./all.md for i in `cat ./Book.txt`; do cat $i \u0026gt;\u0026gt; all.md; echo \u0026#34; \u0026#34; \u0026gt;\u0026gt; all.md ; done pandoc -o all.docx -f markdown -t docx ./all.md Once you write your manuscript, (what the publishing world calls your book text), revise it, copy edit it, and walk backwards in a circle three times, you\u0026rsquo;re ready to publish.\nTools for Publishing I don\u0026rsquo;t have any real firm advice in this area yet since I\u0026rsquo;m still in the midst of it, but I\u0026rsquo;ll share the two options that I\u0026rsquo;m looking at - traditional publishing and self publishing.\nSelf publishing is more easily understood of the two. You can put your book up for sale at any time through Leanpub or Amazon. For better or worse, you have complete control of the content, display, marketing, and revenue of your book.\nTraditional publishing involves finding an literary agent and/or publisher to work with. This route involves pitching your manuscript to someone to represent it through a query. The advantages of this are that, (if you find a good match), you will have a team of people helping you make your book the best it can be and have the possibility of getting it on the shelf in a bookstore. One of the downsides is that the traditional publishing world takes a lot longer than pushing the self publish button.\nWith any luck, I\u0026rsquo;ll have a clearer picture of this all in a bit and be able to share my experiences. In the meantime, I encourage you to grab your keyboard and bring your book ideas to life.\nNo matter the outcome, it\u0026rsquo;s a rewarding journey.\n","permalink":"https://gigasquidsoftware.com/blog/2016/06/19/book-writing-for-the-busy-programmer/","summary":"\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/images/posts/4cb0b445-27492453220_eecdf6dee1.jpg\"\u003e\u003c/p\u003e\n\u003cp\u003eSo you want to write a book?  Awesome.  I\u0026rsquo;ve been working on one too for the last year.\u003c/p\u003e\n\u003cp\u003eNo, it\u0026rsquo;s not really a programming book, but it does have code in it.  It\u0026rsquo;s a sci-fi/fantasy book written for my ten year daughter, but this post isn\u0026rsquo;t about that.  It\u0026rsquo;s about sharing the tools and setup that I\u0026rsquo;ve found work best for me.\u003c/p\u003e\n\u003ch2 id=\"tools-for-writing\"\u003eTools for Writing\u003c/h2\u003e\n\u003cp\u003eIf the first thing you think of when you want to write a book is creating some really cool tools to help you, I can totally relate.  It\u0026rsquo;s a programmer thing.\u003c/p\u003e","title":"Book Writing for the Busy Programmer"},{"content":"\nClojure.spec is an exciting, new core library for Clojure. It enables pragmatic specifications for functions and brings a new level of robustness to building software in Clojure, along with unexpected side benefits. One of which is the ability to write specifications that generate Dr. Seuss inspired rhymes.\nIn this blog post, we\u0026rsquo;ll take a tour of writing specifications for a clojure function, as well as the power of data generation. First, some inspirational words:\nOne fish Two fish Red fish Blue fish The mere shape of these words brings a function to mind. One that would take in a vector:\n[1 2 \u0026#34;Red\u0026#34; \u0026#34;Blue\u0026#34;] and give us back a string of transformed items with the word fish added, of course.\nBut, let us turn our attention the parameters of this function and see how we can further specify them. Before we get started, make sure you use the latest version of clojure, currently [org.clojure/clojure \u0026quot;1.9.0-alpha13\u0026quot;], test.check [org.clojure/test.check \u0026quot;0.9.0\u0026quot;], and add clojure.spec to your namespace.\n(ns one-fish.core (:require [clojure.spec :as s])) Specifying the values of the parameters Back to the parameters. The first two are integers, that\u0026rsquo;s pretty easy, but we want to say more about them. For example, we don\u0026rsquo;t want them to be very big. Having a child\u0026rsquo;s poem with the One Hundred Thousand and Thirty Three fish really won\u0026rsquo;t do. In fact, what we really want is to say is there is finite notion of fish-numbers and it\u0026rsquo;s a map of integer to string representation.\n(def fish-numbers {0 \u0026#34;Zero\u0026#34; 1 \u0026#34;One\u0026#34; 2 \u0026#34;Two\u0026#34;}) Then, we can use the s/def to register the spec we are going to define for global reuse. We\u0026rsquo;ll use a namespaced keyword ::fish-number to express that our specification for a valid number is the keys of the fish-numbers map.\n(s/def ::fish-number (set (keys fish-numbers))) Now that we have the specification, we can ask it if it\u0026rsquo;s valid for a given value.\n(s/valid? ::fish-number 1) ;=\u0026gt; true (s/valid? ::fish-number 5) ;=\u0026gt; false So 5 is not a valid number for us. We can ask it to explain why not.\n(s/explain ::fish-number 5) ;;val: 5 fails spec: :one-fish.core/fish-number predicate: (set (keys fish-numbers)) Which, of course, totally makes sense because 5 is not in our fish-numbers map. Now that we\u0026rsquo;ve covered the numbers, let\u0026rsquo;s look at the colors. We\u0026rsquo;ll use a finite set of colors for our specification. In addition to the classic red and blue, we\u0026rsquo;ll also add the color dun.\n(s/def ::color #{\u0026#34;Red\u0026#34; \u0026#34;Blue\u0026#34; \u0026#34;Dun\u0026#34;}) You may be asking yourself, \u0026ldquo;Is dun really a color?\u0026rdquo;. The author can assure you that it is in fact a real color, like a dun colored horse. Furthermore, the word has the very important characteristic of rhyming with number one, which the author spent way too much time trying to think of.\nSpecifying the sequences of the values We\u0026rsquo;re at the point where we can start specifying things about the sequence of values in the parameter vector. We\u0026rsquo;ll have two numbers followed by two colors. Using the s/cat, which is a concatentation of predicates/patterns, we can specify it as the ::first-line\n(s/def ::first-line (s/cat :n1 ::fish-number :n2 ::fish-number :c1 ::color :c2 ::color)) What the spec is doing here is associating each part with a tag, to identify what was matched or not, and its predicate/pattern. So, if we try to explain a failing spec, it will tell us where it went wrong.\n(s/explain ::first-line [1 2 \u0026#34;Red\u0026#34; \u0026#34;Black\u0026#34;]) ;; In: [3] val: \u0026#34;Black\u0026#34; fails spec: :one-fish.core/color ;; at: [:c2] predicate: #{\u0026#34;Blue\u0026#34; \u0026#34;Dun\u0026#34; \u0026#34;Red\u0026#34;} That\u0026rsquo;s great, but there\u0026rsquo;s more we can express about the sequence of values. For example, the second number should be one bigger than the first number. The input to the function is going to be the map of the destructured tag keys from the ::first-line\n(defn one-bigger? [{:keys [n1 n2]}] (= n2 (inc n1))) Also, the colors should not be the same value. We can add these additional specifications with s/and.\n(s/def ::first-line (s/and (s/cat :n1 ::fish-number :n2 ::fish-number :c1 ::color :c2 ::color) one-bigger? #(not= (:c1 %) (:c2 %)))) We can test if our data is valid.\n(s/valid? ::first-line [1 2 \u0026#34;Red\u0026#34; \u0026#34;Blue\u0026#34;]) ;=\u0026gt; true If we want to get the destructured, conformed values, we can use s/conform. It will return the tags along with the values.\n(s/conform ::first-line [1 2 \u0026#34;Red\u0026#34; \u0026#34;Blue\u0026#34;]) ;=\u0026gt; {:n1 1, :n2 2, :c1 \u0026#34;Red\u0026#34;, :c2 \u0026#34;Blue\u0026#34;} Failing values for the specification can be easily identified.\n(s/valid? ::first-line [2 1 \u0026#34;Red\u0026#34; \u0026#34;Blue\u0026#34;]) ;=\u0026gt; false (s/explain ::first-line [2 1 \u0026#34;Red\u0026#34; \u0026#34;Blue\u0026#34;]) ;; val: {:n1 2, :n2 1, :c1 \u0026#34;Red\u0026#34;, :c2 \u0026#34;Blue\u0026#34;} ;; fails spec: :one-fish.core/first-line predicate: one-bigger? With our specifications for both the values and the sequences of values in hand, we can now use the power of data generation to actually create data.\nGenerating test data - and poetry with specification The s/exercise function will generate data for your specifications. It does 10 items by default, but we can tell it to do only 5. Let\u0026rsquo;s see what it comes up with.\n(s/exercise ::first-line 5) ;; ([(0 1 \u0026#34;Dun\u0026#34; \u0026#34;Red\u0026#34;) {:n1 0, :n2 1, :c1 \u0026#34;Dun\u0026#34;, :c2 \u0026#34;Red\u0026#34;}] ;; [(0 1 \u0026#34;Blue\u0026#34; \u0026#34;Red\u0026#34;) {:n1 0, :n2 1, :c1 \u0026#34;Blue\u0026#34;, :c2 \u0026#34;Red\u0026#34;}] ;; [(0 1 \u0026#34;Blue\u0026#34; \u0026#34;Dun\u0026#34;) {:n1 0, :n2 1, :c1 \u0026#34;Blue\u0026#34;, :c2 \u0026#34;Dun\u0026#34;}] ;; [(1 2 \u0026#34;Blue\u0026#34; \u0026#34;Dun\u0026#34;) {:n1 1, :n2 2, :c1 \u0026#34;Blue\u0026#34;, :c2 \u0026#34;Dun\u0026#34;}] ;; [(1 2 \u0026#34;Dun\u0026#34; \u0026#34;Red\u0026#34;) {:n1 1, :n2 2, :c1 \u0026#34;Dun\u0026#34;, :c2 \u0026#34;Red\u0026#34;}]) Hmmm\u0026hellip; something\u0026rsquo;s not quite right. Looking at the first result [0 1 \u0026quot;Dun\u0026quot; Red\u0026quot;], it would result in:\nZero fish One fish Dun fish Red fish Although, it meets our criteria, it\u0026rsquo;s missing one essential ingredient - rhyming!\nLet\u0026rsquo;s fix this by adding an extra predicate number-rhymes-with-color?.\n(defn fish-number-rhymes-with-color? [{n :n2 c :c2}] (or (= [n c] [2 \u0026#34;Blue\u0026#34;]) (= [n c] [1 \u0026#34;Dun\u0026#34;]))) We\u0026rsquo;ll add this to our definition of ::first-line, stating that the second number parameter should rhyme with the second color parameter.\n(s/def ::first-line (s/and (s/cat :n1 ::fish-number :n2 ::fish-number :c1 ::color :c2 ::color) one-bigger? #(not= (:c1 %) (:c2 %)) fish-number-rhymes-with-color?)) (s/valid? ::first-line [1 2 \u0026#34;Red\u0026#34; \u0026#34;Blue\u0026#34;]) ;=\u0026gt; true (s/explain ::first-line [1 2 \u0026#34;Red\u0026#34; \u0026#34;Dun\u0026#34;]) ;; {:n1 1, :n2 2, :c1 \u0026#34;Red\u0026#34;, :c2 \u0026#34;Dun\u0026#34;} fails spec: ;; :one-fish.core/first-line predicate: fish-number-rhymes-with-color? Now, let\u0026rsquo;s try the data generation again.\n(s/exercise ::first-line) ;; ([(1 2 \u0026#34;Red\u0026#34; \u0026#34;Blue\u0026#34;) {:n1 1, :n2 2, :c1 \u0026#34;Red\u0026#34;, :c2 \u0026#34;Blue\u0026#34;}] ;; [(1 2 \u0026#34;Red\u0026#34; \u0026#34;Blue\u0026#34;) {:n1 1, :n2 2, :c1 \u0026#34;Red\u0026#34;, :c2 \u0026#34;Blue\u0026#34;}] ;; [(0 1 \u0026#34;Blue\u0026#34; \u0026#34;Dun\u0026#34;) {:n1 0, :n2 1, :c1 \u0026#34;Blue\u0026#34;, :c2 \u0026#34;Dun\u0026#34;}] ;; [(1 2 \u0026#34;Dun\u0026#34; \u0026#34;Blue\u0026#34;) {:n1 1, :n2 2, :c1 \u0026#34;Dun\u0026#34;, :c2 \u0026#34;Blue\u0026#34;}] ;; [(1 2 \u0026#34;Dun\u0026#34; \u0026#34;Blue\u0026#34;) {:n1 1, :n2 2, :c1 \u0026#34;Dun\u0026#34;, :c2 \u0026#34;Blue\u0026#34;}] ;; [(0 1 \u0026#34;Blue\u0026#34; \u0026#34;Dun\u0026#34;) {:n1 0, :n2 1, :c1 \u0026#34;Blue\u0026#34;, :c2 \u0026#34;Dun\u0026#34;}] ;; [(1 2 \u0026#34;Red\u0026#34; \u0026#34;Blue\u0026#34;) {:n1 1, :n2 2, :c1 \u0026#34;Red\u0026#34;, :c2 \u0026#34;Blue\u0026#34;}] ;; [(0 1 \u0026#34;Red\u0026#34; \u0026#34;Dun\u0026#34;) {:n1 0, :n2 1, :c1 \u0026#34;Red\u0026#34;, :c2 \u0026#34;Dun\u0026#34;}] ;; [(0 1 \u0026#34;Red\u0026#34; \u0026#34;Dun\u0026#34;) {:n1 0, :n2 1, :c1 \u0026#34;Red\u0026#34;, :c2 \u0026#34;Dun\u0026#34;}] ;; [(0 1 \u0026#34;Blue\u0026#34; \u0026#34;Dun\u0026#34;) {:n1 0, :n2 1, :c1 \u0026#34;Blue\u0026#34;, :c2 \u0026#34;Dun\u0026#34;}]) Much better. To finish things off, let\u0026rsquo;s finally create a function to create a string for our mini-poem from our data. While we\u0026rsquo;re at it, we can use our spec with s/fdef, to validate that the parameters are indeed in the form of ::first-line.\nUsing spec with functions Here\u0026rsquo;s our function fish-line that takes in our values as a parameters.\n(defn fish-line [n1 n2 c1 c2] (clojure.string/join \u0026#34; \u0026#34; (map #(str % \u0026#34; fish.\u0026#34;) [(get fish-numbers n1) (get fish-numbers n2) c1 c2]))) We can specify that the args for this function be validated with ::first-line and the return value is a string.\n(s/fdef fish-line :args ::first-line :ret string?) Now, we turn on the instrumentation of the validation for functions and see what happens. To enable this, we need to add the spec.test namespace to our requires:\n(ns one-fish.core (:require [clojure.spec :as s] [clojure.spec.test :as stest])) The instrument function takes a fully-qualified symbol so add ` before the function name to resolve it in the context of the current namespace.\n(stest/instrument `fish-line) (fish-line 1 2 \u0026#34;Red\u0026#34; \u0026#34;Blue\u0026#34;) ;-\u0026gt; \u0026#34;One fish. Two fish. Red fish. Blue fish.\u0026#34; But what about with bad data?\n(fish-line 2 1 \u0026#34;Red\u0026#34; \u0026#34;Blue\u0026#34;) ;; Call to #\u0026#39;one-fish.core/fish-line did not conform to spec: val: ;; {:n1 2, :n2 1, :c1 \u0026#34;Red\u0026#34;, :c2 \u0026#34;Blue\u0026#34;} fails at: [:args] predicate: ;; one-bigger? :clojure.spec/args (2 1 \u0026#34;Red\u0026#34; \u0026#34;Blue\u0026#34;) ;; {:clojure.spec/problems ;; {[:args] ;; {:pred one-bigger?, ;; :val {:n1 2, :n2 1, :c1 \u0026#34;Red\u0026#34;, :c2 \u0026#34;Blue\u0026#34;}, ;; :via [], ;; :in []}}, ;; :clojure.spec/args (2 1 \u0026#34;Red\u0026#34; \u0026#34;Blue\u0026#34;)} Ah, yes - the first number must be one smaller than the second number.\nWrap up I hope you\u0026rsquo;ve enjoyed this brief tour of clojure.spec. If you\u0026rsquo;re interested in learning more, you should check out the spec.guide. It really is an exciting, new feature to Clojure.\nIn the meantime, I\u0026rsquo;ll leave you with one of our generated lines, sure to be a big hit with future generations.\nZero fish One fish Red fish Dun fish ","permalink":"https://gigasquidsoftware.com/blog/2016/05/29/one-fish-spec-fish/","summary":"\u003cp\u003e\u003cimg loading=\"lazy\" src=\"https://upload.wikimedia.org/wikipedia/en/9/9a/One_Fish_Two_Fish_Red_Fish_Blue_Fish_%28cover_art%29.jpg\"\u003e\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://blog.cognitect.com/blog/2016/5/23/introducing-clojurespec\"\u003eClojure.spec\u003c/a\u003e is an exciting, new core library for Clojure.  It enables pragmatic specifications for functions and brings a new level of robustness to building software in Clojure, along with unexpected side benefits.  One of which is the ability to write specifications that generate Dr. Seuss inspired rhymes.\u003c/p\u003e\n\u003cp\u003eIn this blog post, we\u0026rsquo;ll take a tour of writing specifications for a clojure function, as well as the power of data generation.  First, some inspirational words:\u003c/p\u003e","title":"One Fish Spec Fish"},{"content":"It happened again. I was sitting down reading a paper and I came across the phrase Kolmogorov-Uspensky machine and I had no idea what it was. My initial reaction was just to move on. It probably wasn\u0026rsquo;t important, I told myself, just a detail that I could skim over. I took a sip of my tea and continued on. The next paragraph it appeared again. It was just sticking up like a thread waiting to be pulled. Still, I resisted. After all, I wasn\u0026rsquo;t even near my computer. I would have to get up an walk into the other room. After considering it for a moment, inertia won out and I continued my reading. There it was once more. This time right in the same paragraph, silently mocking me. I knew I had to do something so I strode to my computer and pulled the thread.\nWhat is a Kolmogorov-Uspensky machine? The first thing I found is that the Kolmogorov-Uspensky machine, (also referred to as KUM), is very similar to the Turing machine. In fact, it shares the same computational class of being Turing-complete.\nThe Turing machine operates on a tape divided into cells. The head can move along the tape and read and write to it. The tape is the storage for the machine. Its movements are controlled by a collection of instructions which will be executed if certain prerequisites are met. The difference between the Turing machine and a Kolmogorov-Uspensky machine is that the KUM has a tape that can change topology. It\u0026rsquo;s a graph.\nThe graph of a KUM machine is not just any graph. It\u0026rsquo;s a particular kind of graph. It must have the property that if you start at a one vertex, all the other vertexes are uniquely addressable. The graph also has a active node which, in turn, has a active neighborhood of other nodes associated with it. This is not unlike the Turing machine\u0026rsquo;s head that points to the current cell. To figure out what do, the KUM machine looks at the graph to decide on what instruction to execute. The instructions can consist of adding a node or edge to the active neighborhood, removing a node or edge from the active neighborhood, or halting.\nAfter spending some time reading and researching, I felt like a had some idea of what a Kolmogorov-Uspensky machine was but it was still a bit fuzzy. I wanted to really dig in and experience it by trying to implement one. I found an esoteric programming language called Eodermdrome that fit the bill and set to work building it out in Clojure.\nEodermdrome An Eodermdrome program creates graphs from a string of letters. For example the graph of abcdae would produce\nThe program itself consists of series of commands or rules. The command will be executed if the following prereqs are met:\nThe match graph in the command is a subgraph of the system graph. If an input set is part of the command, the input character read of the system input must match it. A command is of the form:\nmatch-graph graph-replacement This will execute if the match-graph is a subgraph and then transform the match to the replacement. Example:a abc (input-set) match-graph graph-replacement. This will execute if the match is a subgraph and if the next character of the system input matches. On executing, it will read one char from the input and then transform the match graph with the replacement. Example: (1) a abc match-graph (output) graph-replacement. This will execute if the match-graph is a subgraph. On executing, it will print the output to the system and transform the match with the replacement. Example: a (1) abc (input-set) match-graph (output) graph-replacement. This will execute if the match is a subgraph and if the next character of the system input matches. On executing, it will read one char from the input, print the output to the system, and then transform the match graph with the replacement. Example: (0) a (1) abc Comments are also allowed as text in between commas. In this implementation, they must be contained on a single line. Example: ,this is a comment,(1) a abc\nThe initial state of the graph with a program is the denoted by the graph string thequickbrownfoxjumpsoverthelazydog.\nWe now have all we need to walk through an example program in the Kolmogorov-Uspensky machine.\nAn add program Let\u0026rsquo;s take program for adding two string of ones together separated by zeros.\n,takes input of ones separated by zeros and adds the ones, thequickbrownfoxjumpsoverthelazydog a (1) a ab (0) a a ab (1) a Given a system input of \u0026ldquo;101\u0026rdquo;, it will print out \u0026ldquo;11\u0026rdquo;. Let\u0026rsquo;s walk through what happens in the program.\nStep 1 - The program starts with our graph in the initial state of our beloved thequickbrownfoxjumpsoverthelazydog configuration.\nStep 2 - The first instruction matches ,takes input of ones separated by zeros and adds the ones, thequickbrownfoxjumpsoverthelazydog a with he active subgraph being the whole graph. It is replaced by the single graph node a.\nStep 3 - The next instruction set (1) a ab a subgraph matches and takes a 1 off the input and transforms the graph to ab.\nStep 4 - The instruction set (0) a a also matches (since a is a subgraph of ab) and it takes a zero off the input and transforms back the a to a so the graph is still ab.\nStep 5 - The instruction set ab (1) a now matches and a one prints out and the ab graph changes to a.\nStep 6 - Now, the (1) a ab instruction matches, it takes another 1 off the input (our last one) and transforms to ab\nStep 7 - Finally, ab (1) a matches and it prints out a 1 and rewrites the graph to back to a\nThere are no more matching subgraphs without input required for instructions, so the program ends.\nParting thoughts and threads The Kolmogorov-Uspensky machine is quite interesting. Not only is the idea of graph storage and rewriting appealing, it is also pretty powerful compared to Turing machines. In fact, Dima Grigoriev proved that Turing machines cannot simulate Kolmogorov machines in real time.\nIt\u0026rsquo;s been quite a fun and enriching jaunt. The next time you see an unfamiliar term or concept, I encourage you to pull the thread. You never know where it will take you. It\u0026rsquo;s a great way to enlarge your world.\nIf you are interested in the code and hacking for yourself, here is the repo https://github.com/gigasquid/eodermdrome.\nOther good resources on KUM:\nOn Kolmogorov Machines And Related Issues Kolmogorov\u0026rsquo;s Heritage in Mathematics What is a \u0026ldquo;pointer machine\u0026rdquo; ","permalink":"https://gigasquidsoftware.com/blog/2016/03/16/kolmogorov-uspensky-machine/","summary":"\u003cp\u003eIt happened again.  I was sitting down reading a paper and I came across the phrase \u003cem\u003eKolmogorov-Uspensky machine\u003c/em\u003e and I had no idea what it was.  My initial reaction was just to move on.  It probably wasn\u0026rsquo;t important, I told myself, just a detail that I could skim over.  I took a sip of my tea and continued on. The next paragraph it appeared \u003cem\u003eagain\u003c/em\u003e.  It was just sticking up like a thread waiting to be pulled. Still, I resisted.  After all, I wasn\u0026rsquo;t even near my computer.  I would have to get up an walk into the other room.   After considering it for a moment, inertia won out and I continued my reading.  There it was \u003cem\u003eonce more\u003c/em\u003e.  This time right in the same paragraph, silently mocking me.  I knew I had to do something so I strode to my computer and pulled the thread.\u003c/p\u003e","title":" Kolmogorov-Uspensky Machine"},{"content":"\nThis post continues our exploration from the last blog post Why Hyperdimensional Socks Never Match. We are still working our way through Kanerva\u0026rsquo;s paper. This time, with the basics of hypervectors under our belts, we\u0026rsquo;re ready to explore how words can be expressed as context vectors. Once in a high dimensional form, you can compare two words to see how similar they are and even perform reasoning.\nTo kick off our word vector adventure, we need some words. Preferring whimsy over the Google news, our text will be taken from ten freely available fairy tale books on http://www.gutenberg.org/.\nGather ye nouns Our goal is to assemble a frequency matrix, with all the different nouns as the rows and the columns will be the counts of if the word appears or not in the document. Our matrix will be binary with just 1s and 0s. The document will be a sentence or fragment of words. A small visualization is below.\nNoun Doc1 Doc2 flower 1 0 king 0 1 fairy 1 0 gold 1 1 The size of the matrix will be big enough to support hypervector behavior, but not so big as to make computation too annoyingly slow. It will be nouns x 10,000.\nThe first task is to get a set of nouns to fill out the rows. Although, there are numerous online sources for linguistic nouns, they unfortunately do not cover the same language spectrum as old fairy tale books. So we are going to collect our own. Using Stanford CoreNLP, we can collect a set of nouns using Grimm\u0026rsquo;s Book as a guide. There are about 2500 nouns there to give us a nice sample to play with. This makes our total matrix size ~ 2500 x 10,000.\nNow that we have our nouns, let\u0026rsquo;s get down to business. We want to create an index to row to make a noun-idx and then create a sparse matrix for our word frequency matrix.\n(ns hyperdimensional-playground.context-vectors (:require [clojure.core.matrix :as m] [clojure.core.matrix.linear :as ml] [clojure.string :as string] [hyperdimensional-playground.core :refer [rand-hv cosine-sim mean-add inverse xor-mul]] [hyperdimensional-playground.fairytale-nouns :refer [fairy-tales-nouns book-list]])) (m/set-current-implementation :vectorz) ;; size of the hypervectors and freq matrix columns (def sz 10000) ;; The nouns come from a sampling of Grimm\u0026#39;s fairy tale nouns these will ;; make up the rows in the frequency matrix (def noun-idx (zipmap fairy-tales-nouns (range))) (def freq-matrix (m/new-sparse-array [(count fairy-tales-nouns) sz])) The next thing we need to do is to have some functions to take a book, read it in, split it into documents and then update the frequency matrix.\nRandom indexing for the win The interesting thing about the update method is that we can use random indexing. We don\u0026rsquo;t need to worry about having a column for each document. Because of the nature of hyperdimensions, we can randomly assign 10 columns for each document.\n(defn update-doc! \u0026#34;Given a document - upate the frequency matrix using random indexing\u0026#34; [doc] (let [known-nouns (clojure.set/intersection fairy-tales-nouns (set doc))] ; use positive random indexing (doall (repeatedly 10 #(doseq [noun known-nouns] (m/mset! freq-matrix (get noun-idx noun) (rand-int sz) 1)))))) The whole book is processed by slurping in the contents and using a regex to split it up into docs to update the matrix.\n(defn process-book \u0026#34;Load a book and break it into sentence like documents and update the frequency matrix\u0026#34; [book-str] (let [book-text (slurp book-str) docs (partition 25 (map string/lower-case (string/split book-text #\u0026#34;\\s|\\.|\\,|\\;|\\!|\\?\u0026#34;))) doc-count (count docs)] (println \u0026#34;processing:\u0026#34; book-str \u0026#34;(with\u0026#34; doc-count \u0026#34;docs)\u0026#34;) (doall (map-indexed (fn [idx doc] (when (zero? (mod idx 1000)) (println \u0026#34;doc:\u0026#34; idx)) (update-doc! doc)) docs)) (println \u0026#34;DONE with \u0026#34; book-str))) We can now run the whole processing with:\n(doseq [book book-list] (process-book book)) On my system, it only takes about 3 seconds.\nGreat! Now we have hypervectors associated with word frequencies. They are now context word vectors. What can we do with them.\nHow close is a king to a goat? One of the things that we can do with them is find out a measure of how closely related the context of two words are by a measure of their cosine similarity. First, we need a handy function to turn a string word into a word vector by getting it out of our frequency matrix.\n(defn wv [word] \u0026#34;Get a hypervector for the word from the frequency matrix\u0026#34; (let [i (get noun-idx word)] (assert (not (nil? i)) (str word \u0026#34; not found\u0026#34;)) (m/slice freq-matrix i))) Then we can make another nice function to compare two words and give a informational map back.\n(defn compare-wvs \u0026#34;Compare two words and give the cosine distance info map\u0026#34; [word1 word2] (let [wv1 (wv word1) wv2 (wv word2)] (when (not= word1 word2) {:word1 word1 :word2 word2 :cosine (cosine-sim wv1 wv2)}))) Let\u0026rsquo;s take a look at the similarities of some words to king.\n(sort-by :cosine[(compare-wvs \u0026#34;king\u0026#34; \u0026#34;queen\u0026#34;) (compare-wvs \u0026#34;king\u0026#34; \u0026#34;prince\u0026#34;) (compare-wvs \u0026#34;king\u0026#34; \u0026#34;princess\u0026#34;) (compare-wvs \u0026#34;king\u0026#34; \u0026#34;guard\u0026#34;) (compare-wvs \u0026#34;king\u0026#34; \u0026#34;goat\u0026#34;)]) ;; ({:word1 \u0026#34;king\u0026#34;, :word2 \u0026#34;goat\u0026#34;, :cosine 0.1509151478896664} ;; {:word1 \u0026#34;king\u0026#34;, :word2 \u0026#34;guard\u0026#34;, :cosine 0.16098893367403827} ;; {:word1 \u0026#34;king\u0026#34;, :word2 \u0026#34;queen\u0026#34;, :cosine 0.49470535530616655} ;; {:word1 \u0026#34;king\u0026#34;, :word2 \u0026#34;prince\u0026#34;, :cosine 0.5832521795716931} ;; {:word1 \u0026#34;king\u0026#34;, :word2 \u0026#34;princess\u0026#34;, :cosine 0.5836922474743367}) As expected, the royal family is closer to the king then a guard or goat is.\nOne of the interesting things is that now we can do addition and subtraction with these word vectors and see how it affects the relation with other words.\nBoy + Gold = King, Boy + Giant = Jack We can take a look at how close boy and king are together by themselves.\n(cosine-sim (wv \u0026#34;boy\u0026#34;) (wv \u0026#34;king\u0026#34;)) ;=\u0026gt; 0.42996397142253145 Now we can add some gold to the boy and that new word vector will be closer to king than boy was alone.\n(cosine-sim (mean-add (wv \u0026#34;boy\u0026#34;) (wv \u0026#34;gold\u0026#34;)) (wv \u0026#34;king\u0026#34;)) ;=\u0026gt; 0.5876251031366048 Doing the same for boy and jack, we find that adding a giant moves the context closer.\n(cosine-sim (wv \u0026#34;boy\u0026#34;) (wv \u0026#34;jack\u0026#34;)) ;=\u0026gt; 0.33102858702785953 ;; boy + giant = jack (cosine-sim (mean-add (wv \u0026#34;giant\u0026#34;) (wv \u0026#34;boy\u0026#34;)) (wv \u0026#34;jack\u0026#34;)) ;=\u0026gt;0.4491473187787431 Amusingly, a frog and a princess make a prince.\n;;; frog + princess = prince (cosine-sim (wv-add \u0026#34;frog\u0026#34; \u0026#34;princess\u0026#34;) (wv \u0026#34;prince\u0026#34;)) ;=\u0026gt; 0.5231641991974249 We can take this even farther by subtracting words and adding others. For example a similarity to the word queen can be obtained by subtracting man from king and adding woman.\n;;; queen= (king-man) + woman (cosine-sim (wv \u0026#34;queen\u0026#34;) (mean-add (wv \u0026#34;woman\u0026#34;) (wv-subtract \u0026#34;king\u0026#34; \u0026#34;man\u0026#34;))) ;=\u0026gt;0.5659832204544486 Similarly, a contextual closeness to father can be gotten from subtracting woman from mother and adding man.\n(cosine-sim (wv \u0026#34;father\u0026#34;) (mean-add (wv \u0026#34;man\u0026#34;) (wv-subtract \u0026#34;mother\u0026#34; \u0026#34;woman\u0026#34;))) ;=\u0026gt;0.5959841177719538 But wait, that\u0026rsquo;s not all. We can also do express facts with these word vectors and reason about them.\nReasoning with word vector with the database as a hyperdimensional value The curious nature of hypervectors allows the storage of multiple entity, attributes in it and allow the retrieval of the likeness of them later by simple linear math - using only xor multiplication and addition. This gives us the database as a value in the form of a high dimensional vector.\nFor an example, say we want to express the fact that Hansel is a brother of Gretel. We can do this by adding the xor product of brother with hansel and the product of brother with Gretel.\n;; hansel is the brother of gretel ;; B*H + B*G (def hansel-brother-of-gretel (mean-add (xor-mul (wv \u0026#34;brother\u0026#34;) (wv \u0026#34;hansel\u0026#34;)) (xor-mul (wv \u0026#34;brother\u0026#34;) (wv \u0026#34;gretel\u0026#34;)))) Also we can express that Jack is a brother of Hansel.\n(def jack-brother-of-hansel (mean-add (xor-mul (wv \u0026#34;brother\u0026#34;) (wv \u0026#34;jack\u0026#34;)) (xor-mul (wv \u0026#34;brother\u0026#34;) (wv \u0026#34;hansel\u0026#34;)))) We can add these two facts together to make a new hypervector value.\n(def facts (mean-add hansel-brother-of-gretel jack-brother-of-hansel)) Now we can actually reason about them and ask questions. Is Jack a brother of Hansel? With a high cosine similarity, we can assume the answer is likely.\n;; is jack the brother of hansel? (cosine-sim (wv \u0026#34;jack\u0026#34;) (xor-mul (mean-add (wv \u0026#34;brother\u0026#34;) (wv \u0026#34;gretel\u0026#34;)) facts)) ;=\u0026gt;0.8095270629815969 What about someone unrelated. Is Cinderella the brother of Gretel? - No\n;; is cinderella the brother of gretel ? (cosine-sim (wv \u0026#34;cinderella\u0026#34;) (xor-mul (mean-add (wv \u0026#34;brother\u0026#34;) (wv \u0026#34;gretel\u0026#34;)) facts)) ;=\u0026gt;0.1451799916656951 Is Jack the brother of Gretel - Yes\n;; is jack the brother of gretel ? (cosine-sim (wv \u0026#34;jack\u0026#34;) (xor-mul (mean-add (wv \u0026#34;brother\u0026#34;) (wv \u0026#34;gretel\u0026#34;)) facts)) ;=\u0026gt; 0.8095270629815969 We can take this further by adding more facts and inventing a relation of our own.\nSiblings in Hyperspace Let\u0026rsquo;s invent a new word vector that is not in our nouns - siblings. We are going to create new random hypervector to represent it.\n(def siblings (rand-hv)) We will define it in terms of word vectors that we already have. That is, siblings will be a the sum of brother + sister. We XOR multiply it by siblings to associate it with the hypervector.\n(def siblings-brother-sister (mean-add (xor-mul siblings (wv \u0026#34;brother\u0026#34;)) (xor-mul siblings (wv \u0026#34;sister\u0026#34;)))) Now we can add some more facts. Gretel is a sister of Hansel.\n;; gretel is the sister of hansel ;; S*G + S*H (def gretel-sister-of-hansel (mean-add (xor-mul (wv \u0026#34;sister\u0026#34;) (wv \u0026#34;gretel\u0026#34;)) (xor-mul (wv \u0026#34;sister\u0026#34;) (wv \u0026#34;hansel\u0026#34;)))) Gretel is also a sister of Jack.\n;; gretel is the sister of jack ; S*G + S*H (def gretel-sister-of-jack (mean-add (xor-mul (wv \u0026#34;sister\u0026#34;) (wv \u0026#34;gretel\u0026#34;)) (xor-mul (wv \u0026#34;sister\u0026#34;) (wv \u0026#34;jack\u0026#34;)))) Collecting all of our facts into one hypervector (as a database).\n(def facts (mean-add hansel-brother-of-gretel jack-brother-of-hansel gretel-sister-of-jack gretel-sister-of-hansel siblings-brother-sister)) Now we can ask some for questions.\nAre Hansel and Gretel siblings? - Yes\n;; are hansel and gretel siblings? (cosine-sim (mean-add (wv \u0026#34;hansel\u0026#34;) (wv \u0026#34;gretel\u0026#34;)) (xor-mul siblings facts)) ;=\u0026gt;0.627015379034067 Are John and Roland siblings - No\n;; are john and roland siblings? (cosine-sim (mean-add (wv \u0026#34;roland\u0026#34;) (wv \u0026#34;john\u0026#34;)) (xor-mul siblings facts)) ;=\u0026gt; 0.1984017637065277 Are Jack and Hansel siblings? - Yes\n(cosine-sim (mean-add (wv \u0026#34;jack\u0026#34;) (wv \u0026#34;hansel\u0026#34;)) (xor-mul siblings facts)) ;=\u0026gt;0.48003572523507465 It is interesting to think of that nothing is stopping us at this point from retracting facts by simply subtracting the fact encoded word vectors from our \u0026ldquo;database\u0026rdquo; value and making a new value from it.\nConclusions In this fun, but casual exploration of word vector we have seen the potential for reasoning about language in a way that uses nothing more complicated than addition and multiplication. The ability to store dense information in hypervectors, extract it with simple methods, and flexibly collect it randomly, shows its versatility and power. Hyperdimensional vectors might hold the key to unlocking a deeper understanding of cognitive computing or perhaps even true artificial intelligence.\nIt is interesting to note that this technique is not limited to words. Other applications can be done the same way. For example a video recommendation using a hypervector with movie titles. Or perhaps even anomaly detection using sensor readings over a regular weekly time period.\nLooking over our journey with word vectors. At the beginning it seemed that word vectors were magical. Now, after an understanding of the basics, it still seems like magic.\nIf you are interested in exploring further, feel free to use my github hyperdimensional-playground as a starting point.\n","permalink":"https://gigasquidsoftware.com/blog/2016/02/10/fairy-tale-word-vectors/","summary":"\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/images/posts/606aa6f7-24654386380_bda44419a8_n.jpg\"\u003e\u003c/p\u003e\n\u003cp\u003eThis post continues our exploration from the last blog post \u003ca href=\"http://gigasquidsoftware.com/blog/2016/02/06/why-hyperdimensional-socks-never-match/\"\u003eWhy Hyperdimensional Socks Never Match\u003c/a\u003e.  We are still working our way through \u003ca href=\"http://redwood.berkeley.edu/pkanerva/papers/kanerva09-hyperdimensional.pdf\"\u003eKanerva\u0026rsquo;s paper\u003c/a\u003e.  This time, with the basics of hypervectors under our belts, we\u0026rsquo;re ready to explore how words can be expressed as context vectors.  Once in a high dimensional form, you can compare two words to see how similar they are and even perform reasoning.\u003c/p\u003e\n\u003cp\u003eTo kick off our word vector adventure, we need some words.  Preferring whimsy over the Google news, our text will be taken from ten freely available fairy tale books on \u003ca href=\"http://www.gutenberg.org/\"\u003ehttp://www.gutenberg.org/\u003c/a\u003e.\u003c/p\u003e","title":"Fairy Tale Word Vectors"},{"content":"\nThe nature of computing in hyperdimensions is a strange and wonderful place. I have only started to scratch the surface by reading a paper by Kanerva. Not only is it interesting from a computer science standpoint, it\u0026rsquo;s also interesting from a cognitive science point of view. In fact, it could hold the key to better model AI and general reasoning. This blog is a casual stroll through some of the main points of Kanerva\u0026rsquo;s paper along with examples in Clojure to make it tangible. First things first, what is a hyperdimension?\nWhat is a Hyperdimension and Where Are My Socks? When we are talking about hyperdimensions, we are really talking about lots of dimensions. A vector has dimensions. A regular vector could have three dimensions [0 1 1], but a hyperdimensional vector has tons more, like 10,000 or 100,000. We call these big vectors hypervectors for short, which makes them sound really cool. Although the vectors could be made up of anything, we are going to use vectors made up of zeros and ones. To handle big computing with big vectors in a reasonable amount of time, we are also going to use sparse vectors. What makes them sparse is that most of the space is empty, (zeros). In fact, Clojure has a nice library to handle these sparse vectors. The core.matrix project from Mike Anderson is what we will use in our examples. Let\u0026rsquo;s go ahead and make some random hypervectors.\nFirst we import the core.matrix libraries and set the implementation to vectorz which provides fast double precision vector math.\n(ns hyperdimensional-playground.core (:require [clojure.core.matrix :as m] [clojure.core.matrix.linear :as ml])) (m/set-current-implementation :vectorz) Next we set the sz of our hypervectors to be 100,000. We also create a function to generate a random sparse hypervector by choosing to put ones in about 10% of the space.\n(def sz 100000) (defn rand-hv [] (let [hv (m/new-sparse-array [sz]) n (* 0.1 sz)] (dotimes [i n] (m/mset! hv (rand-int sz) 1)) hv)) Now we can generate some.\n(def a (rand-hv)) (def b (rand-hv)) (def c (rand-hv)) (def d (rand-hv)) a ;=\u0026gt; #vectorz/vector Large vector with shape: [100000] You can think of each of this hypervectors as random hyperdimensional sock, or hypersock, because that sounds cooler. These hypersocks, have curious properties. One of which is that they will ~never match.\nHypersocks never match Because we are dealing with huge amount of dimensions, a mathematically peculiar probability distribution occurs. We can take a random hypervector to represent something, then take another one and they will different from each by about 100 STD. We can take another one and it too, will be 100 STD from the other ones. For practical purposes, we will run out of time before we will run of vectors that are unrelated. Because of this, any two hypersocks will never match each other.\nHow can we tell how similar two hypersocks are? The cosine to tell the similarity between two vectors. This is determined by the dot product. We can construct a cosine similarity function to give us a value from -1 to 1 to measure how alike they are with 1 being the same and -1 being the complete opposite.\n(defn cosine-sim [v1 v2] (/ (m/dot v1 v2) (* (ml/norm v1) (ml/norm v2)))) If we look at the similarity of a hypervector with itself, the result is ~1. With the other random hypervectors, it is ~0.\n(cosine-sim a a) ;=\u0026gt; 1.0 (cosine-sim d d) ;=\u0026gt; 1.0 (cosine-sim a b) ;=\u0026gt; 0.0859992468320239 (cosine-sim b c) ;=\u0026gt; 0.09329186588790261 (cosine-sim a c) ;=\u0026gt; 0.08782018973001954 There are other cool things we can do with hypervectors, like do math with them.\nThe Hamming Distance of Two Hypersocks We can add hypervectors together with a sum mean vector. We add the vector of 1s and 0s together then we divide the resulting vector by the number of total vectors. Finally, to get back to our 1s and 0s, we round the result.\n(defn mean-add [\u0026amp; hvs] (m/emap #(Math/round (double %)) (m/div (apply m/add hvs) (count hvs)))) The interesting thing about addition is that the result is similar to all the vectors in it. For example, if we add a and b together to make x, x = a + b, then x will be similar to a and similar to b.\n;; x = a + b (def x (mean-add a b)) (cosine-sim x a) ;=\u0026gt; 0.7234734658023224 (cosine-sim x b) ;=\u0026gt; 0.7252586504505658 You can also do a very simple form of multiplication on vectors with 1s and 0s with using XOR. We can do this by add the two vectors together and then mapping mod 2 on each of the elements.\n(defn xor-mul [v1 v2] (-\u0026gt;\u0026gt; (m/add v1 v2) (m/emap #(mod % 2)))) We can actually use this xor-mul to calculate the Hamming distance, which is an important measure of error detection. The Hamming distance is simply the sum of all of the xor multiplied elements.\n(defn hamming-dist [v1 v2] (m/esum (xor-mul v1 v2))) (hamming-dist [1 0 1] [1 0 1]) ;=\u0026gt; 0 (hamming-dist [1 0 1 1 1 0 1] [1 0 0 1 0 0 1]) ;=\u0026gt; 2 (hamming-dist a a) ;=\u0026gt; 0 This illustrates a point that xor multiplication randomizes the hypervector, but preserves the distance. In the following example, we xor multiply two random hypervectors by another and the hamming distance stays the same.\n; xa = x * a ; ya = y * a ; hamming distance of xa is the same as ya ;; multiplication randomizes but preserves the distance (def x (rand-hv)) (def y (rand-hv)) (def xa (xor-mul x a)) (def ya (xor-mul y a)) (hamming-dist xa ya) ;=\u0026gt; 1740.0 (hamming-dist x y) ;=\u0026gt; 1740.0 So you can xor multiply your two hypersocks and move them to a different point in hyperspace, but they will still be the same distance apart.\nAnother great party trick in hyperspace, is the ability to bind and unbind hypervectors for use as map like pairs.\nUsing Hypervectors to Represent Maps A map of pairs is a very important data structure. It gives the ability to bind symbols to values and then retrieve those values. We can do this with hypervectors too. Consider the following structure:\n{:name \u0026#34;Gigasquid\u0026#34; :cute-animal \u0026#34;duck\u0026#34; :favorite-sock \u0026#34;red plaid\u0026#34;} We can now create hypervectors to represent each of these values. Then we can xor the hypervector symbol to the hypervector value and sum them up.\n;; data records with bound pairs (def x (rand-hv)) ;; favorite-sock (def y (rand-hv)) ;; cute-animal (def z (rand-hv)) ;; name (def a (rand-hv)) ;; red-plaid (def b (rand-hv)) ;; duck (def c (rand-hv)) ;; gigasquid ;H = X * A + Y * B + Z * C (def h (mean-add (xor-mul x a) (xor-mul y b) (xor-mul z c))) Now, we have a sum of all these things and we want to find the value of the favorite sock. We can unbind it from the sum by xor multiplying the favorite-sock hypervector x. Because of the property that xor multiplication both distributes and cancels itself out.\n(hamming-dist (xor-mul x (xor-mul x a)) a) ;=\u0026gt; 0 We can compare the result with the known values and find the closest match.\n(hamming-dist a (xor-mul x h)) ;=\u0026gt; 1462.0 ;; closest to \u0026#34;red-plaid\u0026#34; (hamming-dist b (xor-mul x h)) ;=\u0026gt; 1721.0 (hamming-dist c (xor-mul x h)) ;=\u0026gt; 1736.0 (cosine-sim a (xor-mul x h)) ;=\u0026gt; 0.3195059768353112 ;; closest to \u0026#34;red-plaid\u0026#34; (cosine-sim b (xor-mul x h)) ;=\u0026gt; 0.1989075567830733 (cosine-sim c (xor-mul x h)) ;=\u0026gt; 0.18705233578983288 Conclusion We have seen that the nature of higher dimensional representation leads to some very interesting properties with both representing data and computing with it. These properties and others form the foundation of exciting advancements in Cognitive Computing like word vectors. Future posts will delve further into these interesting areas. In the meantime, I encourage you to read Kanerva\u0026rsquo;s paper on your own and to find comfort in that when you can\u0026rsquo;t find one of your socks, it\u0026rsquo;s not your fault. It most likely has something to do with the curious nature of hyperspace.\nThanks to Ross Gayler for bringing the paper to my attention and to Joe Smith for the great conversations on SDM\n","permalink":"https://gigasquidsoftware.com/blog/2016/02/06/why-hyperdimensional-socks-never-match/","summary":"\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/images/posts/f03495f5-7188420611_a99f936971_n.jpg\"\u003e\u003c/p\u003e\n\u003cp\u003eThe nature of computing in hyperdimensions is a strange and wonderful place.   I have only started to scratch the surface by reading a paper by \u003ca href=\"http://redwood.berkeley.edu/pkanerva/papers/kanerva09-hyperdimensional.pdf\"\u003eKanerva\u003c/a\u003e. Not only is it interesting from a computer science standpoint, it\u0026rsquo;s also interesting from a cognitive science point of view.  In fact, it could hold the key to better model AI and general reasoning.  This blog is a casual stroll through some of the main points of Kanerva\u0026rsquo;s paper along with examples in Clojure to make it tangible.  First things first, what is a hyperdimension?\u003c/p\u003e","title":"Why Hyperdimensional Socks Never Match"},{"content":" Book of Software Miracles - Cover This 21st century illustrated manuscript was recently uncovered. It depicts miraculous phenomena in software engineering and represents one of the most spectacular new discoveries in the field of Renaissance Computer Science.\nSome examples of the glorious illustrations and text translations are presented here.\nBook of Software Miracles Fol. 26 On the day in 1958 that John McCarthy invented LISP, three suns appeared in the East in the morning sky which moved towards each other so that they merged into one.\nBook of Software Miracles Fol. 72 In the year 1952, countless software bugs appeared in the land after being coined by Grace Hopper during the invention of the COBOL language.\nBook of Software Miracles Fol. 83 In the year of 2007, a great and wonderful comet appeared in the sky. This was followed by the invention of the Clojure language by Rich Hickey.\nBook of Software Miracles Fol. 91 A month after the NPM Node repository burst its banks in the year of 2015, a wondrous creature appeared from the JavaScript ecosystem. Found dead after the raging subsided, was in this shape and form and is painted here.\nFor more information about this remarkable book visit Book of Software Miracles\n","permalink":"https://gigasquidsoftware.com/blog/2016/01/16/book-of-software-miracles/","summary":"\u003cfigure\u003e\n    \u003cimg loading=\"lazy\" src=\"/images/posts/128ec10e-23811303563_029d4c864e_c.jpg\"\n         alt=\"Book of Software Miracles - Cover\"/\u003e \u003cfigcaption\u003e\n            Book of Software Miracles - Cover\n        \u003c/figcaption\u003e\n\u003c/figure\u003e\n\n\u003cp\u003eThis 21st century illustrated manuscript was recently uncovered.  It depicts miraculous phenomena in software engineering and represents one of the most spectacular new discoveries in the field of Renaissance Computer Science.\u003c/p\u003e\n\u003cp\u003eSome examples of the glorious illustrations and text translations are presented here.\u003c/p\u003e\n\u003cfigure\u003e\n    \u003cimg loading=\"lazy\" src=\"/images/posts/8171c9ae-24070311299_c23fc388e0_z.jpg\"\n         alt=\"Book of Software Miracles Fol. 26\"/\u003e \u003cfigcaption\u003e\n            Book of Software Miracles Fol. 26\n        \u003c/figcaption\u003e\n\u003c/figure\u003e\n\n\u003cp\u003e\u003cem\u003eOn the day in 1958 that John McCarthy invented LISP, three suns appeared in the East in the morning sky which moved towards each other so that they merged into one.\u003c/em\u003e\u003c/p\u003e","title":"Book of Software Miracles"},{"content":"\nAll programming languages are not created equal. Some clearly excel at solving different problems. There are languages that are great for scalability and others that are great for proving correctness. But what about one that that will make you smarter? To look for this answer, I am going to turn to a different language, our human language, and research from the field of linguistics and cognitive development.\nA new language is born Up until the late 1970s, there was no school for the deaf In Nicaragua. Being deaf before then meant only developing crude signs with your family and friends. Beyond that there was nothing. Finally, the wife of the dictator set up a special school for them. This was the first time that the children were brought together in one place rather than being scattered about. For most of them, it was the first time that they had ever met another deaf person. There were about fifty kids in that first class and they came together with fifty different ways of communication with crude gestures. But after awhile, something amazing happened. They started to converge into a common system - a language was born. For scientists, this was an incredible opportunity to watch a new language develop. One of the fascinating insights had to do with how the this sign language evolved over the generations of children entering the school. One in particular, was a study about how words in a language can actually increase your cognitive capacity and make people smarter.\nThe study involved a test that was performed on different generations of students from the school, including the very first students who were now grown and younger children. A comic strip shown to the participants. In it there are two brothers. The big brother is playing with the train and the little brother wants the play with it. The big brother puts it under the bed and goes out to the kitchen to get a sandwich. While the big brother is gone, the little brother takes out the train and hides it in the toy box. The question for the test subjects is, \u0026ldquo;When the big brother comes back, where is he going to look for the train?\u0026rdquo;\nThinking about thinking For most kids over the age of five, the answer will be that the big brother will look under the bed because he doesn\u0026rsquo;t know that it has been moved to the toy box. The interesting thing was that the first generation of kids that went through the school, now thirty five years old, failed this simple test. The younger ones all passed. What was going on?\nTo find out, the scientists looked a differences in the language over the generations and found that the older signers lacked words for the concept of thinking. The earlier generation just had one word for think, while the later generations had evolved ten or twelve. Words that expressed concepts like understand and believe. It seems that having words gave them access to a concept that otherwise would have been really hard to think about. It increased their cognitive capacity. It enabled them to think about thinking.\nThinking about programming programs Programming languages allow us to translate our human thoughts and instructions to machines. We have words to express simple concepts like adding two numbers together with + or finding how many elements are in a list with count, but what about harder concepts that are more difficult to access? Is there an analogy to having words to think about thinking that some programming languages have that others don\u0026rsquo;t? I believe there is. It\u0026rsquo;s having a way to think about a program programming itself with self modifying code or macros.\nIn Clojure, macros are way to do meta-programming. This involves ability to treat the program as data, allowing a program to modify another program - even its own. It gives Clojure the capability to implement language features, make code more concise, and encapsulate patterns and repetitive code. It is a powerful feature and more to the point of our current line of inquiry, it is a pretty friggin difficult concept to grok. In fact, before I was exposed to a language that had macros in it, I doubt that I would have been able to think about it. For the sake of argument, let\u0026rsquo;s go back to the comic strip story with the two brothers. But this time, the train is a function and the little brother uses a macro on it when the big brother gets a snack in the kitchen. What does the big brother expect the result of the program to be when he gets back in the room. Prior to my exposure to Clojure and macros, I am sure I would have failed the test.\nConclusion So yes, I do think that a programming language can increase your cognitive capacity and make you smarter. I certainly feel that my exposure had expanded my world and given me access to programming concepts that I did not have with my other programming experience. I also feel certain that there are other languages out there, both existing and yet to be invented, that have words to express concepts that am not even aware of. Languages that are just waiting for me to expand my horizons.\nAnd that certainty makes me incredibly happy and grateful to be a programmer.\nListen to whole fascinating story of Ann Senghas studying sign language that born in Nicaragua on Radiolab\n","permalink":"https://gigasquidsoftware.com/blog/2015/12/20/can-a-programming-language-make-you-smarter/","summary":"\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/images/posts/4ea49f2a-118425909_86f332f075_z.jpg\"\u003e\u003c/p\u003e\n\u003cp\u003eAll programming languages are not created equal.  Some clearly excel at solving different problems.  There are languages that are great for scalability and others that are great for proving correctness.  But what about one that that will make you smarter?  To look for this answer, I am going to turn to a different language, our human language, and research from the field of linguistics and cognitive development.\u003c/p\u003e\n\u003ch3 id=\"a-new-language-is-born\"\u003eA new language is born\u003c/h3\u003e\n\u003cp\u003eUp until the late 1970s, there was no school for the deaf In Nicaragua.  Being deaf before then meant only developing crude signs with your family and friends.  Beyond that there was nothing.  Finally, the wife of the dictator set up a special school for them.  This was the first time that the children were brought together in one place rather than being scattered about.  For most of them, it was the first time that they had ever met another deaf person.  There were about fifty kids in that first class and they came together with fifty different ways of communication with crude gestures.  But after awhile, something amazing happened. They started to converge into a common system - a language was born. For scientists, this was an incredible opportunity to watch a new language develop.  One of the fascinating insights had to do with how the this sign language evolved over the generations of children entering the school.  One in particular, was a study about how words in a language can actually increase your cognitive capacity and make people \u003cem\u003esmarter\u003c/em\u003e.\u003c/p\u003e","title":"Can a Programming Language Make You Smarter?"},{"content":"\nThe last time I went to the dentist to get a cavity filled, I got a shot of Novocain as a local anesthetic to numb the area. After I emerged from the dental chair, I still had no feeling in my lip and mouth area. Trying to talk and smile was comical. Trying to drink tea resulting in dribbles down my face. Luckily, the loss of feeling only lasted a couple hours. Soon, I was back to normal. Even in this small and common scenario, we can see the close link between motion and sensory perception. What would happen if you couldn\u0026rsquo;t feel your whole body?\nThis is exactly what happened in the tragic and amazing story of Ian Watermann. At age 19, he had what appeared to be the flu, but was actually a rare disease of the nervous system that left him unable to feel any sensation of touch below the neck. Unable to process this sensory information, he was totally unable to walk or move his body. This is despite the fact that his motor system was left almost untouched by the disease. He had the capacity to move, but without the sensory feedback he was paralyzed.\nIan was told that he would spend the rest of his life in a wheelchair, but in an inspiring show of determination he recovered mobility. With the help of physiotherapists, he retrained his brain to substitute visual feedback for touch feedback. He could move his hands and legs while he could see them. Finally, he could walk again with his sight and concentration. If the visual feedback is taken away, (lights turned off), the ability to move vanishes.\nFeedback is the essential ingredient for human motion. But what about businesses, startups, and software projects? One of the challenges that all of these face is the ability to move fast. This ability to move is not unlike that in our own bodies. Movement and action are a result of a complex, interdependent system. In the case of businesses, they are made of people, technology, and processes. Like the human body, it is critically dependent on feedback. A business can have the capacity for action, but without the ability to process feedback it is essentially immobilized.\nIf you want to move fast, single most important thing you can do is to improve your feedback at every level.\nIf you want to add new technology, ask how it improves your feedback.\nFeedback from the market Feedback from your users Feedback from your operational systems Feedback from your code Feedback from your employees Feedback from yourself The best feedback systems are distributed and multi-layered. A single market feedback signal to the CEO is good, but much better is one that gets shared among the many facets of a company. A distributed and interconnected network of feedback will help companies and projects be responsive, fast, nimble, and resilient.\nThe next time you hear, \u0026ldquo;How can we go faster\u0026rdquo;?\u0026quot; ask the question \u0026ldquo;How can we increase feedback?\u0026rdquo; You\u0026rsquo;ll be on the right track to fly.\n","permalink":"https://gigasquidsoftware.com/blog/2015/12/19/the-key-to-moving-fast-is-feedback/","summary":"\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/images/posts/fa6ce410-1809288965_c84080f2d3_n.jpg\"\u003e\u003c/p\u003e\n\u003cp\u003eThe last time I went to the dentist to get a cavity filled, I got a shot of Novocain as a local anesthetic to numb the area.  After I emerged from the dental chair, I still had no feeling in my lip and mouth area.\nTrying to talk and smile was comical.  Trying to drink tea resulting in dribbles down my face.  Luckily, the loss of feeling only lasted a couple hours.  Soon, I was back to normal.  Even in this small and common scenario, we can see the close link between motion and sensory perception.  What would happen if you couldn\u0026rsquo;t feel your whole body?\u003c/p\u003e","title":"The Key to Moving Fast is Feedback"},{"content":"\nIt\u0026rsquo;s that time of the year again for radars. Since I made one last year, I decided to continue the tradition and make one this year.\nLanguages No changes from last year for Clojure and Pixie.\nAdopt: Clojure - It is fantastic language. Trial: Pixie - The language continues to grow and improve and has a great community - and it is a LISP. Assess: Elixir - Another great functional language leveraging the Erlang VM. It has a lot of energy in the community. Hold: Java - There are plenty of other great alternatives out there on the JVM. Cute Animals Alpacas have moved up from trial last year, and Llamas to hold. Alpacas are clearly more fluffy.\nAdopt: Alpacas - Like llamas only fluffier. Trial: Quokkas - Where does Australia get this cutie? Assess: Tardigrades - or Water Bear - They are the cutest microscopic creature out there. Hold: Llamas - Not as fluffy as they could be. Artificial Intelligence I haven\u0026rsquo;t been too into robots this year, so the category has been changed to AI.\nAdopt: Weka - A collection of machine learning algorithms and explorers. I was very impressed with it when I tried it on a speech acts classifier project. Trial: Word Vectors - A way to encode words and leverage training so that you can see the relation between them. For example, a dog is closer to the word wolf than cat. Assess: Tensor Flow - I have only scratched the surface with this, but it is an exciting open source computational pipeline for machine learning (and other things). The tutorials are pretty amazing in quality alone. Hold: Logical Inference - This is pretty bold, but I base it on Professor Geoff Hinton\u0026rsquo;s Deep Learning talk (at 33:00) where he explains that thought vectors, (made from word vectors), will be able to perform natural reasoning with only linear algebra. The grand dream of old fashioned strong AI, will then be realized in a completely different way. Tasty Food Adopt: Stilton Cheese - The king of cheeses. Trial: Cocoa Nibs - I have to admit I am getting into crunching on some nibs in the afternoon. Best of all, no sugar! Assess: Cold Sake - I was firmly in the warm sake camp, until I tried some very nice cold sakes. However, in the winter, warm is so nice \u0026hellip; Hold: Fruit Cake - Traditions are important, but sometimes you need to let it go. Special Thanks The radar this year was generated by a cool github project that uses Clojure and Quill to generate the image based off of a json config file. So go out there and make a radar of your own.\nHappy Holidays!\n","permalink":"https://gigasquidsoftware.com/blog/2015/12/08/gigasquids-radar-2015/","summary":"\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/images/posts/139be10b-23249736219_dfa625309b_c.jpg\"\u003e\u003c/p\u003e\n\u003cp\u003eIt\u0026rsquo;s that time of the year again for \u003cem\u003eradars\u003c/em\u003e.  Since I made \u003ca href=\"http://gigasquidsoftware.com/blog/2014/12/17/gigasquids-radar-2014/\"\u003eone last year\u003c/a\u003e, I decided to continue the tradition and make one this year.\u003c/p\u003e\n\u003ch2 id=\"languages\"\u003eLanguages\u003c/h2\u003e\n\u003cp\u003eNo changes from last year for Clojure and Pixie.\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cem\u003eAdopt\u003c/em\u003e: Clojure - It is fantastic language.\u003c/li\u003e\n\u003cli\u003e\u003cem\u003eTrial\u003c/em\u003e: \u003ca href=\"https://github.com/pixie-lang/pixie\"\u003ePixie\u003c/a\u003e - The language continues to grow and improve and has a great community - and it is a LISP.\u003c/li\u003e\n\u003cli\u003e\u003cem\u003eAssess\u003c/em\u003e: \u003ca href=\"http://elixir-lang.org/\"\u003eElixir\u003c/a\u003e - Another great functional language leveraging the Erlang VM.   It has a lot of energy in the community.\u003c/li\u003e\n\u003cli\u003e\u003cem\u003eHold\u003c/em\u003e: Java - There are plenty of other great alternatives out there on the JVM.\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"cute-animals\"\u003eCute Animals\u003c/h2\u003e\n\u003cp\u003eAlpacas have moved up from \u003cem\u003etrial\u003c/em\u003e last year, and Llamas to \u003cem\u003ehold\u003c/em\u003e.  Alpacas are clearly more fluffy.\u003c/p\u003e","title":"Gigasquid's Radar 2015"},{"content":"We humans are quite wonderful. We do amazing things every day without even realizing it. One of them, you are doing right now. You are reading text. Your brain is taking these jumbles of letters and spaces in this sentence, which in linguist terms is called an utterance, and making sense out of it. The individual meanings of sentences might be quite complex.\nTake for example the utterance, \u0026ldquo;I like cheese\u0026rdquo;. To understand it properly, you need to know the meanings of the individual words. In particular, you would need to know that cheese is a tasty food stuff that is made from milk. This would be a detailed and full understanding. But there is a higher level of understanding that we can look at called Speech Acts.\nSpeech Acts are way of classifying our communication according to purposes. We perform speech acts when we ask questions, make statements, requests, promises, or even just say thanks. These speech acts cross languages. When I ask a question in English, it is the same speech act as if I ask it in French. In fact, if we were to travel to another planet with aliens, we can assume if they had a language, it would involve speech acts. It should be no surprise then, to communicate effectively with machines, it will have to understand speech acts.\nTo explore this communication we are going to consider only three speech acts:\nStatements - \u0026ldquo;I like cheese.\u0026rdquo; Questions - \u0026ldquo;How do you make cheese?\u0026rdquo; Expressives - \u0026ldquo;Thank you\u0026rdquo; Our goal is to have our program be able to tell the difference between these three speech acts - without punctuation.\nWhy not use punctuation? If you are having a conversation with a human over Slack or some other chat channel, you may or may not put in a question mark or period. To have a computer be able to converse as naturally with a human as another human, it will have to understand the speech act without the aid of punctuation.\nGenerally, we want to have the computer:\nRead in an utterance/text that may or may not have punctuation. Classify whether the result is a statement, question, or expressive. To tackle this problem, we are going to have to break this up into two main parts. The first is parsing the text and annotating it with data. The second is to classify the text based on the data from the parsing.\nParsing and Annotating Text with Stanford CoreNLP The Stanford CoreNLP is considering the state of the art for POS, (Part of Speech), tagging and other linguistic annotations. It also is a Java library, so very easy to use from Clojure.\nHere we are using a simple wrapper library called stanford-talk to take in some text and process it. The result is a list of tokens for each word in the :token-data map. Each token is annotated with the POS tag. There is a lot more data in the annotations that we can look at to give us insight into this text. But, to keep things simple, we are just going to look at the POS speech tag at the moment.\n(process-text \u0026#34;I like cheese\u0026#34;) ;{:token-data ; ({:sent-num 0, :token \u0026#34;I\u0026#34;, :pos \u0026#34;PRP\u0026#34;, :net \u0026#34;O\u0026#34;, :lemma \u0026#34;I\u0026#34;, :sentiment \u0026#34;Neutral\u0026#34;} ; {:sent-num 0, :token \u0026#34;like\u0026#34;, :pos \u0026#34;VBP\u0026#34;, :net \u0026#34;O\u0026#34;, :lemma \u0026#34;like\u0026#34;, :sentiment \u0026#34;Neutral\u0026#34;} ; {:sent-num 0, :token \u0026#34;cheese\u0026#34;, :pos \u0026#34;NN\u0026#34;, :net \u0026#34;O\u0026#34;, :lemma \u0026#34;cheese\u0026#34;, :sentiment \u0026#34;Neutral\u0026#34;}), ; :refs [[{:sent-num 0, :token \u0026#34;I\u0026#34;, :gender \u0026#34;UNKNOWN\u0026#34;, :mention-type \u0026#34;PRONOMINAL\u0026#34;, :number \u0026#34;SINGULAR\u0026#34;, :animacy \u0026#34;ANIMATE\u0026#34;};]]} So the text \u0026ldquo;I like cheese\u0026rdquo; has the following POS tags list of all POS tags:\nI = PRP Personal Pronoun like = VBP Verb, non-3rd person singular present cheese - Noun, singular or mass This is great. We have some data about the text we can analyze. The next thing to do is to figure out how to classify the text based on this data.\nClassification with Weka Weka is a collection of machine learning algorithms. There is a program for interactive exploration of data sets, as well as a java library so you can use it programatically. Speaking of data sets, we need some. Just having one sentence about liking cheese is not going to get us very far with any machine learning.\nSo where can you go to get conversational questions and statements on the internet? Well, one place that is pretty good for that is answers.com. We can scrape some pages for questions and answers. Enough so that we can collect and cleanup some input files of\n~ 200 statements ~ 200 questions The expressives were a bit more difficult. Let\u0026rsquo;s just make a list of about 80 of them.\nNow, we have a list of text data. We need to decide on some features and generate some input files to train the classifiers on.\nChoosing Features for Classification First, what is a feature? A feature is some sort of encoding of the data that the computer is going to consider for classification. For example, the number of nouns in a sentence could be a feature. There is a whole field of study dedicated to figuring out what the best features for data for machine learning are. Again, to keep things simple, we can take an educated guess on some features based on a good paper:\nSentence length Number of nouns in the sentence (NN, NNS, NNP, NNPS) If the sentence ends in a noun or adjective (NN, NNS, NNP, NNPS, JJ, JJR, JJS) If the sentence begins in a verb (VB, VBD, VBG, VBP, VPZ) The count of the wh, (like who, what) markers (WDT, WRB, WP, WP$) We can now go through our data file, generate our feature data, and output .arff file format to ready it as training file for weka.\nRaw question file example:\nWhat is floater exe Is bottled water or tap water better for your dog How do you treat lie bumps on the tongue Can caffeine be used in powder form Arff file with features\n@relation speechacts @attribute sen_len numeric @attribute nn_num numeric @attribute end_in_n numeric @attribute begin_v numeric @attribute wh_num numeric @attribute type {assertion,question,expressive} @data 4,2,1,0,1,question 10,4,1,0,0,question 9,3,1,0,1,question 7,3,1,0,0,question Now that we have our input file to training our machine learning algorithms, we can start looking at classifiers.\nChoosing the Classifier Using the weka explorer, we can try out different classification models. For this data, the best one seems to be the Random Forest. In the explorer, it beat out Naive Bayes and J48. It is also worth mentioning that we are not using a separate source of test data, we are cross validating on the original training set. If we wanted to be more rigorous, we could collect more data and cut it in half, using one set for the training and one set for the testing.\nNow that we have a classifier, we can create some Clojure code with the java library to use it.\nUsing the Weka Classifier from our Clojure Code After importing the needed Java classes into our Clojure code, we can create the Random Forest classifier.\n(def classifier (new RandomForest)) We then create a function that will load our arff input file as a datasource\n(defn get-datasource [fname] (new ConverterUtils$DataSource (.getResourceAsStream (clojure.lang.RT/baseLoader) fname))) And another uses it to train the classifier, returning a map of the evaluator and data that we will need for our predictions.\n(defn train-classifier [fname] (let [source (get-datasource fname) data (.getDataSet source) _ (.setClassIndex data (dec (.numAttributes data))) _ (.buildClassifier classifier data) e (new Evaluation data)] (.crossValidateModel e classifier data (.intValue (int 10)) (new Random 1) (into-array [])) (println (.toSummaryString e)) {:evaluator e :data data})) Now, we need to be able to ask about a classification for a particular instance of new data. This is going to be where we are parsing new text and asking for an answer from our trained model. To do this, we need to generate an instance for the evaluation to look at. It is constructed from numbers in the same order as our arff file. The exception is that we are not going to provide a value for the final field of the speech act type. We will assign that to the a missing value.\n(defn gen-instance [dataset [val0 val1 val2 val3 val4]] (let [i (new Instance 6)] (doto i (.setValue 0 (double val0)) (.setValue 1 (double val1)) (.setValue 2 (double val2)) (.setValue 3 (double val3)) (.setValue 4 (double val4)) (.setValue 5 (Instance/missingValue)) (.setDataset dataset)))) Now we can use this function in a prediction function to get our answer back\n(defn predict [ev d vals] (let [v (.evaluateModelOnce ev classifier (gen-instance d vals))] (case v 0.0 :statement 1.0 :question 2.0 :expressive))) Calling the predict function would look something like:\n(def results (train-classifier \u0026#34;speech-acts-input-all.arff\u0026#34;)) (def predictor (:evaluator results)) (def data (:data results)) (predict predictor data [1 1 1 0 0]) ;; -\u0026gt; :expressive Now that we have the parsing piece and the classification piece, we can put everything together.\nPutting it all together We finally have all the details we need write a classify-text function.\n(defn classify-text [text] (let [stats (parser/gen-stats text) features [(:sen-len stats) (:nn-num stats) (:end-in-n stats) (:begin-v stats) (:wh-num stats)]] (weka/predict predictor data features))) (classify-text \u0026#34;I like cheese\u0026#34;) ;; -\u0026gt; :statement (classify-text \u0026#34;How do you make cheese\u0026#34;) ;; -\u0026gt; :question (classify-text \u0026#34;Right on\u0026#34;) ;; -\u0026gt; :expressive Yea! It worked. We finally have something that will read in text and tell us its best guess of a speech act, all without punctuation. Let\u0026rsquo;s quickly review what we have done.\nSummary Gather data sets of statements, questions, and expressives Parse text and annotate it with POS tags using Stanford CoreNLP Choose features of the data to analyze and generate arff files Use Weka explorer to try out the best classification algorithims Programatically use weka to train classifier and predict a new instance Write a program to tie it all together It\u0026rsquo;s funny how a simple thing like asking whether something is a statement or question gets you knee deep in Natural Language Processing and Machine Learning pretty fast.\nWe\u0026rsquo;ve learned a lot, now let\u0026rsquo;s have a bit of fun. Now that we can classify speech acts, we can make a sort of proto chat bot with a really limited responses.\nProto Chat Bot Here we are going to be a bit loose and actually check if a question mark is used. If it is, we will automatically mark it as a question. Otherwise, we will classify it.\n(defn respond [text] (let [question-mark? (re-find #\u0026#34;\\?$\u0026#34; text) type (if question-mark? :question (classify-text text))] (case type :question \u0026#34;That is an interesting question.\u0026#34; :statement \u0026#34;Nice to know.\u0026#34; :expressive \u0026#34;:)\u0026#34;))) We just need a quick repl and main function now:\n(defn repl [] (do (print \u0026#34;\u0026gt;\u0026gt; \u0026#34;) (flush)) (let [input (read-line)] (if-not (= input \u0026#34;quit\u0026#34;) (do (println (try (c/respond input) (catch Exception e (str \u0026#34;Sorry: \u0026#34; e \u0026#34; - \u0026#34; (.getMessage e))))) (recur)) (do (println \u0026#34;Bye!\u0026#34;) (System/exit 0))))) (defn -main [\u0026amp; args] (println \u0026#34;Hello. Let\u0026#39;s chat.\u0026#34;) (flush) (repl)) Testing it out with lein run, we can have a little chat:\nHello. Let\u0026#39;s chat. \u0026gt;\u0026gt; Hi :) \u0026gt;\u0026gt; Do you know where I can go to buy cheese That is an interesting question. \u0026gt;\u0026gt; I am a big cheese fan Nice to know. \u0026gt;\u0026gt; you are quite smart Nice to know. \u0026gt;\u0026gt; bye :) Want more? Check out the code https://github.com/gigasquid/speech-acts-classifier.\nSpecial thanks to Paul deGrandis for allowing me to pick his awesome brain on AI things\n","permalink":"https://gigasquidsoftware.com/blog/2015/10/20/speech-act-classification-for-text-with-clojure/","summary":"\u003cp\u003eWe humans are quite wonderful.  We do amazing things every day without even realizing it.  One of them, you are doing right now.  You are reading text.  Your brain is taking these jumbles of letters and spaces in this sentence, which in linguist terms is called an \u003ca href=\"https://en.wikipedia.org/wiki/Utterance\"\u003eutterance\u003c/a\u003e, and making sense out of it.  The individual meanings of sentences might be quite complex.\u003c/p\u003e\n\u003cp\u003eTake for example the utterance, \u0026ldquo;I like cheese\u0026rdquo;.  To understand it properly, you need to know the meanings of the individual words.  In particular, you would need to know that cheese is a tasty food stuff that is made from milk.  This would be a detailed and full understanding.  But there is a higher level of understanding that we can look at called \u003ca href=\"https://en.wikipedia.org/wiki/Utterance\"\u003eSpeech Acts\u003c/a\u003e.\u003c/p\u003e","title":"Speech Act Classification for Text with Clojure"},{"content":"\nThis is a continuation of the first and second conversations in which topics such as creating databases, learning facts, querying, and time traveling were discussed. Today\u0026rsquo;s topics include architecture, caching, and scaling.\nHuman: Hello again Datomic. Ready to talk again?\nDatomic: Sure. I think you wanted to ask me some questions about how I would fit in with your other systems.\nHuman: Yes. Like I was saying earlier, I think your abilities to learn facts, reason about them, and keep track of the history of all those facts is really great. I am interested in having you work with me every day, but first I want to understand your components so that I can make sure you are a good fit for us.\nDatomic: I would be happy to explain my architecture to you. Perhaps showing you this picture is the best way to start.\nI am made of three main parts: my transactors, my peers, and my storage.\nHuman: What is a peer?\nDatomic: A peer is an application that is using the peer library. In our last conversations, we were talking through the Clojure api with datomic.api. The application, or process, that is running this api is called a peer. There can be many of these, all having conversations with me.\nHuman: The peers then talk to your transactor?\nDatomic Yes. The peers talk to my transactor whenever you call transact with the peer library. It is the central coordinator between all the peers and processes the requests using ACID transactions, and then sends the facts off to storage.\nHuman: Could you remind me what ACID stands for again? I always forget. The first one is Atomic right?\nDatomic: That is right. I am Atomic in that every transaction you send to me is all or nothing. If for some reason, one part of it fails, I will reject the entire transaction and leave my database unchanged.\nThe C is for Consistency. This means that I provide every peer with a consistent view of facts over time and transactions. I provide a global ordering of transactions across all the peers with my transactor and peers will always see all the transactions up to their current time without any gaps.\nHuman: What if a peer is behind the global time? How do they catch up to know about the new facts that were transacted by a different peer?\nDatomic: After one peer sends me a successful transaction with some new facts, I will notify all the peers about them.\nHuman: Cool. That takes care of the A and C in ACID. What about the I?\nDatomic: It stands for Isolated. It makes sure that even through there are many peers having conversations with me, transactions are executed serially. This happens naturally with my transactor. Since there is only one transactor, transactions are always executed serially.\nHuman: In the picture, why are there are two transactors then?\nDatomic: Oh, that is for High Availability. When I startup my system, I can launch two running transactors, but hold one in reserve. Just on the off chance something happens to the main one, I will swap in the failover one to keep things running smoothly.\nThe final D in ACID is for Durability. Once a transaction has been committed by my transactor, it is shipped off to storage for safe keeping.\nHuman: What exactly is this storage?\nDatomic: Instead of storing datoms, I send segments, which are closely related datoms, to storage. I have quite a few options for storage:\nDev mode - which just runs within my transactor and writes to the local file system. SQL database DynamoDB Cassandra Riak Couchbase Infinispan memory cluster Human: Which one is the best to use?\nDatomic: The best one to use is the one that you are already have in place at work. This way, I can integrate seamlessly with your other systems.\nHuman: Oh, we didn\u0026rsquo;t really talk about caching. Can you explain how you do that?\nDatomic: Certainly. It is even worth another picture.\nEach peer has a its own working set of recent datoms along with a index to all the rest of the datoms in storage in memory. When the peer has a query for a datom, it first checks to see if it has it locally in its memory cache. If it can\u0026rsquo;t find it there, then it will ask for a segment of that datom from storage. Storage will return that datom along with other related datoms in that segment so that the peer can cache that in memory to make it faster for the next query.\nHuman: That seems really different from other databases, where the client constantly requests queries from a server.\nDatomic: Yes. When most questions can be answered from the local memory, responses are really fast. You don\u0026rsquo;t need to hit storage unless you really need too. You can even add an extra layer of caching with memcached.\nHuman: That sounds great. I can\u0026rsquo;t wait tell you about all of our data. We talked a bit about your querying ability earlier, can you do the same queries that our other standard relational databases do, like joins?\nDatomic: Oh yes. In fact, with me, you don\u0026rsquo;t need to specify your joins explicitly. I use Datalog, which is based on logic, so my joins are implicit. I will figure out exactly what I need to put together to answer your query without you having to spell it out for me.\nHuman: Ok. I know that I can map some of my data that is already in other database tables to you. What about other types of irregular data, like graphs, or sparse data.\nDatomic: I am actually very proud of my data model. It is extremely flexible. Since I store things on such a granular datom level, you don\u0026rsquo;t need to map your logical data model to my physical model. I can handle rectangular table shaped data quite happily along with graph data, sparse data, or other non-rectangular data.\nHuman: That sounds great. What do I need to know about your scaling?\nDatomic: I really excel at reads. All you have to do is elastically add another peer to me for querying. I am not really a good fit for write scale, like big data, or log file analysis. You will find me most happy with data that is valuable information of record and has history that is important, like transaction, medical, or inventory data. I am also really good at being flexible for development and operations since I can use many different types of storage. I have worked with many web and cloud apps.\nHuman: Thanks for answering all my questions. I think you might fit in quite well with our other systems.\nDatomic: Great!\nHuman: One more thing, this conversation has been great, but do you have any training resources for me and my other human coworkers?\nDatomic: Sure thing. There are a few really good resources on the Datomic Training Site. I would suggest watching the videos there and pairing them with:\nThe slides for the videos which have the labs to work through form the videos. The Day of Datomic Repo which has lots of great examples to play with. Tne Datomic Development Resources, which include the docs on the Clojure API Also, if you want to confirm that your data is good fit for me, I suggest you describe your data to the Datomic Google Group. They are nice and knowledgeable group of humans.\nHuman: Thanks again Datomic! I will grab another cookie and check it out!\nDatomic: What is it with humans and cookies?\u0026hellip;\n","permalink":"https://gigasquidsoftware.com/blog/2015/08/25/conversations-with-datomic-part-3/","summary":"\u003cp\u003e\u003cimg loading=\"lazy\" src=\"https://avatars0.githubusercontent.com/u/1478702?v=3\u0026s=200\"\u003e\u003c/p\u003e\n\u003cp\u003e\u003cem\u003eThis is a continuation of the \u003ca href=\"http://gigasquidsoftware.com/blog/2015/08/15/conversations-with-datomic/\"\u003efirst\u003c/a\u003e and\n\u003ca href=\"http://gigasquidsoftware.com/blog/2015/08/19/conversations-with-datomic-part-2/\"\u003esecond\u003c/a\u003e conversations in which topics such as creating databases,\nlearning facts, querying, and time traveling were discussed.  Today\u0026rsquo;s topics include architecture, caching, and scaling.\u003c/em\u003e\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eHuman:\u003c/strong\u003e  Hello again \u003ca href=\"http://www.datomic.com/\"\u003eDatomic\u003c/a\u003e. Ready to talk again?\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eDatomic:\u003c/strong\u003e Sure.  I think you wanted to ask me some questions about how I would fit in with your other systems.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eHuman:\u003c/strong\u003e Yes.  Like I was saying earlier, I think your abilities to learn facts, reason about them, and keep track of the history of all those facts is really great.\nI am interested in having you work with me every day, but first I want to understand your components so that I can make sure you are a good fit for us.\u003c/p\u003e","title":"Conversations with Datomic - Part 3"},{"content":"\nThe following is a continuation of the first conversation which touched on schema creation and querying. This conversation includes learning new facts, time, and the sometimes unfortunate reality of lawyers.\nHuman: Hi Datomic. I am back from my tea and cookies break. I really enjoyed talking with you, could we continue our conversation?\nDatomic: Certainly. Let me see, where did we leave off?\nHuman: Let me check my notes. Oh yes, we had created a database and filled it with facts about some dogs and owners. You showed me how to ask you things about the facts, like which dogs liked cheese.\nDatomic: Ah yes. We were just getting to the really interesting part about how I learn new facts without forgetting the past ones.\nHuman: Can you please explain a bit more about how you learn new facts?\nDatomic: Sure. I learn facts when you tell me to add a new fact about some entity, or to retract a fact about it. It will probably make more sense with an example. Let\u0026rsquo;s take the dog with the name \u0026ldquo;Tiny\u0026rdquo; that I know about. Could you please ask me about the dog and all of the attributes?\nHuman: Alright.\n(d/pull (d/db conn) \u0026#39;[*] [:dog/name \u0026#34;Tiny\u0026#34;]) Datomic:\n{:db/id 17592186045423 :dog/name \u0026#34;Tiny\u0026#34; :dog/breed \u0026#34;Great Dane\u0026#34; :dog/favorite-treat \u0026#34;Cheese\u0026#34;} There is an entity (dog) with the name \u0026ldquo;Tiny\u0026rdquo; who is a Great Dane and his favorite-treat is Cheese. I am not really sure why the Cheese is capitalized, but I am sure it makes sense to a human.\nHuman: Oh right. Well, now that you mention it, I am not really sure about the cheese thing either. Can I just remove that fact?\nDatomic: Well, you can tell me to retract that fact by sending me a transaction in the form of [:db/retract entity-id attribute value]. In the case of the dog, since the name attribute is unique, you can just give me the selector for Tiny like this [:dog/name \u0026quot;Tiny\u0026quot;].\nHuman: Like this?\n(d/transact conn [[:db/retract [:dog/name \u0026#34;Tiny\u0026#34;] :dog/favorite-treat \u0026#34;Cheese\u0026#34;]]) Datomic: Exactly. I have retracted that fact about \u0026ldquo;Tiny\u0026rdquo;. Go ahead and ask me about all of Tiny\u0026rsquo;s attributes again.\nHuman: Ok. I use (d/db conn) for the current database value right?\nDatomic: Yes. But if you are going to be asking me multiple questions about this database value, you should not repeat the (d/db conn) all the time.\nHuman: Oh. What should I do instead?\nDatomic: The connection with me is like a ref. Just like other refs, you should deref it once to get the database value and then use the value repeatedly. This single database value will provide consistency for all your queries.\nHuman: That makes sense.\n(def db-tiny-no-cheese (d/db conn)) (d/pull db-tiny-no-cheese \u0026#39;[*] [:dog/name \u0026#34;Tiny\u0026#34;]) Datomic:\n{:db/id 17592186045423, :dog/name \u0026#34;Tiny\u0026#34;, :dog/breed \u0026#34;Great Dane\u0026#34;} Tiny is a Great Dane.\nHuman: So you don\u0026rsquo;t know anything about the :dog/favorite-treat for \u0026ldquo;Tiny\u0026rdquo;?\nDatomic: At this particular time, I do not have anything to assert about the favorite-treat of Tiny. However, I still remember everything about all the facts that you have told me. For each transaction that you send me, I have a notion of a point in time like t0, t1, t2. I have a complete database value for each one of those points in time. In fact, you can look at all of my assertions and retractions that I have learned about using the d/history function on the database value. This asks me to expose my history, which is normally hidden in favor of the present. I will return back a special database containing all the assertions and retractions across time. Any queries that you ask me will have a fifth datom field to help you distinguish the difference.\nHuman: A fifth datom field?\nDatomic: A datom consists of the following parts: the entity, the attribute, the value, transaction, and an operation which tells you if the fact was added or retracted (e a v tx op). Why don\u0026rsquo;t you try using the d/history function to ask me about all the facts having to do with Tiny? I suggest using the datalog query\n\u0026#39;[:find ?e ?a ?v ?tx ?op :in $ :where [?e :dog/name \u0026#34;Tiny\u0026#34;] [?e ?a ?v ?tx ?op]] which will return all the entity, attribute, value, transaction, and operation facts I ever knew about Tiny.\nHuman: Ok. Here goes.\n(d/q \u0026#39;[:find ?e ?a ?v ?tx ?op :in $ :where [?e :dog/name \u0026#34;Tiny\u0026#34;] [?e ?a ?v ?tx ?op]] (d/history db-tiny-no-cheese)) Datomic:\n#{[17592186045423 63 \u0026#34;Tiny\u0026#34; 13194139534314 true] [17592186045423 64 \u0026#34;Great Dane\u0026#34; 13194139534314 true] [17592186045423 65 \u0026#34;Cheese\u0026#34; 13194139534314 true] [17592186045423 65 \u0026#34;Cheese\u0026#34; 13194139534320 false]} During one transaction, you told me to add three facts about an entity:\nThe :dog/name attribute, (which I refer to as 63), has the value of \u0026ldquo;Tiny\u0026rdquo;. The :dog/breed attribute, (which I refer to as 64), has the value of \u0026ldquo;Great Dane\u0026rdquo;. The :dog/favorite-treat attribute, (which I refer to as 65), has the value of \u0026ldquo;Cheese\u0026rdquo;. During another transaction, you told me to retract a fact regarding the attribute :dog/favorite-treat about the same entity.\nHuman: Wow, that is really cool. Is there a way that I can travel back in time to see the world as it was during that first transaction?\nDatomic: Yes. I am practically a Tardis. You can use the d/as-of function with a database value and the transaction number and you can time travel. Using that time traveled database value, you can ask me about all the facts I knew as of that time.\nHuman: I can\u0026rsquo;t wait to try this. Ok, let\u0026rsquo;s go back to the time when I first asserted the fact that Tiny liked cheese.\n(d/pull (d/as-of db-tiny-no-cheese 13194139534314) \u0026#39;[*] [:dog/name \u0026#34;Tiny\u0026#34;]) Datomic: Hold on. We are time traveling!\n{:db/id 17592186045423 :dog/name \u0026#34;Tiny\u0026#34; :dog/breed \u0026#34;Great Dane\u0026#34; :dog/favorite-treat \u0026#34;Cheese\u0026#34;} Tiny is a Great Dane whose favorite treat is Cheese.\nHuman: Fantastic! Let\u0026rsquo;s go back to the future now, ummm I mean present. Time is a bit wibbly wobbly.\nDatomic: Just take the as-of function off of the database value and you will be back in the present.\nHuman: Hmmm\u0026hellip; Do I have to do a retract every time I want to change a value? For example, the dog named Fido has a favorite treat of a Bone right now, right?\n(d/pull db-tiny-no-cheese \u0026#39;[*] [:dog/name \u0026#34;Fido\u0026#34;]) Datomic:\n{:db/id 17592186045421 :dog/name \u0026#34;Fido\u0026#34; :dog/breed \u0026#34;Mix\u0026#34; :dog/favorite-treat \u0026#34;Bone\u0026#34;} Yes, it is a \u0026ldquo;Bone\u0026rdquo;.\nHuman: So, if I want to change it to be \u0026ldquo;Eggs\u0026rdquo;, do I need to retract the current value of \u0026ldquo;Bone\u0026rdquo; first and then add the fact of \u0026ldquo;Eggs\u0026rdquo;?\nDatomic: You certainly could do that and I would understand you perfectly. However, if you simply assert a new value for an existing attribute, I will automatically add the retraction for you.\nHuman: Cool.\n(d/transact conn [{:db/id [:dog/name \u0026#34;Fido\u0026#34;] :dog/favorite-treat \u0026#34;Eggs\u0026#34;}]) (d/pull (d/db conn) \u0026#39;[*] [:dog/name \u0026#34;Fido\u0026#34;]) Datomic\n{:db/id 17592186045421 :dog/name \u0026#34;Fido\u0026#34; :dog/breed \u0026#34;Mix\u0026#34; :dog/favorite-treat \u0026#34;Eggs\u0026#34;} Fido now has a favorite-treat of \u0026ldquo;Eggs\u0026rdquo;.\nHuman: This is really neat. You never forget any facts?\nDatomic: Nope. Well, except in really exceptional circumstances that usually involve lawyers.\nHuman: Lawyers?\nDatomic: Sigh. Yes, well in some unique situations, you might be under a legal obligation to really forget certain facts and totally remove them from the database. There is a special tool that you can use to excise the data. However, I will store a fact that something was deleted at that time. I just won\u0026rsquo;t be able to remember what.\nHuman: That doesn\u0026rsquo;t sound fun.\nDatomic: I prefer to keep all my facts intact.\nHuman: I can definitely see that. Well, on a happier subject, I have been very impressed with you during our conversations. Having a time traveling database that can reason about facts seems like a really useful thing. Also, you are also really nice.\nDatomic: Awww shucks, thanks. For a human, you are really nice too.\nHuman: I was thinking about the possibility of you coming and working with me every day. Would you mind chatting some more to me about your architecture? I want to understand how your would fit with our other systems.\nDatomic: Certainly. I would love that. Do you want to talk about it now, or have another cookie break first?\nHuman: Now that you mention cookies\u0026hellip; Let\u0026rsquo;s take a short break and we will talk again soon.\n(P.S. Humans, there are some great Datomic Training Videos if you want to learn more)\n","permalink":"https://gigasquidsoftware.com/blog/2015/08/19/conversations-with-datomic-part-2/","summary":"\u003cp\u003e\u003cimg loading=\"lazy\" src=\"https://avatars0.githubusercontent.com/u/1478702?v=3\u0026s=200\"\u003e\u003c/p\u003e\n\u003cp\u003e\u003cem\u003eThe following is a continuation of the first \u003ca href=\"http://gigasquidsoftware.com/blog/2015/08/15/conversations-with-datomic/\"\u003econversation\u003c/a\u003e which touched on schema creation and querying.  This conversation includes learning new facts, time, and the sometimes unfortunate reality of lawyers.\u003c/em\u003e\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eHuman:\u003c/strong\u003e  Hi \u003ca href=\"http://www.datomic.com/\"\u003eDatomic\u003c/a\u003e.  I am back from my tea and cookies break.  I really enjoyed talking with you, could we continue our conversation?\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eDatomic:\u003c/strong\u003e Certainly.  Let me see, where did we leave off?\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eHuman:\u003c/strong\u003e Let me check my \u003ca href=\"https://gist.github.com/gigasquid/92a1effb14fe4f6ced59\"\u003enotes\u003c/a\u003e.  Oh yes, we had created a database and filled it with facts about some dogs and owners.  You showed me how to ask you things about the facts, like which dogs liked cheese.\u003c/p\u003e","title":"Conversations with Datomic Part 2"},{"content":"\nHuman: Hi Datomic. I have been hearing good things about you. I would like to talk to you and get to know you. Is that alright?\nDatomic: Sure! I would be happy to talk with you. What language would you like to converse in?\nHuman: I like Clojure.\nDatomic: That is one of my favorites too. You know how to setup a Leiningen project right?\nHuman: Oh yes. What dependency should I use?\nDatomic: Just use [com.datomic/datomic-free \u0026quot;0.9.5206\u0026quot;].\nHuman: Got it. Do you mind if I record our conversation in a namespaced file, so that I can refer back to it later?\nDatomic: Not a problem. Make sure to require datomic.api when you set it up.\n(ns conversations.datomic (require [datomic.api :as d])) Human: All right. I am all setup up. I don\u0026rsquo;t really know where to start, so maybe you can tell me a little about yourself.\nDatomic: I would be happy to. I am a database of facts. Would you like to create a database with me?\nHuman: Sure. How do I do that?\nDatomic: For a casual conversation like this, we can use a in memory database with a uri like this:\n(def uri \u0026#34;datomic:mem://first-conversation\u0026#34;) Then we can create the database and simply connect to it.\n(d/create-database uri) (def conn (d/connect uri)) Human: So, being a database, obviously you store things. What sort of things to you store?\nDatomic: I store facts about things, which I call datoms.\nHuman: That sound neat. How do I tell you a fact to store? For example, what if I want you to store a fact about a dog, like its name?\nDatomic: Ah. Well the name of a dog is an attribute. First, you need to tell me about the name attribute, so that I can use it to store the fact for you . You can describe the attribute in the form of a map like this:\n{:db/id (d/tempid :db.part/db) :db/ident :dog/name :db/valueType :db.type/string :db/cardinality :db.cardinality/one :db/unique :db.unique/identity :db/doc \u0026#34;Name of the Dog\u0026#34; :db.install/_attribute :db.part/db} This map is a set of facts, (called datoms), about an entity. In this case, the entity is an attribute. Attributes, in turn, can be used to describe other entities, like a dog. I will explain the different parts to you.\ndb/id is the internal id of the fact. With (d/tempid :db.part/db), I will generate it for you, so you don\u0026rsquo;t have to worry about it. db/ident is the human readable reference for it. While I am fine just referring to the attribute by an id, humans prefer text. This says that you can refer to this attribute by the namespaced keyword :dog/name. db/valueType tells me the type of the attribute. The dog\u0026rsquo;s name is a string. db/cardinality lets me know if there is a one-to-one relationship with the entity or not. In our case, a dog has only one name. db/unique is if that attribute is unique for an entity. In our example case, we are saying that a dog can be uniquely identified by its name. db/doc is some documentation for humans that explains a bit more about the attribute. db.install/_attribute tells me that this is an schema attribute that I should store with the other things like it. Human: I think I understand. Let me try one out for myself. So dog breed would be this?\n{:db/id (d/tempid :db.part/db) :db/ident :dog/breed :db/valueType :db.type/string :db/cardinality :db.cardinality/one :db/doc \u0026#34;Breed of the Dog\u0026#34; :db.install/_attribute :db.part/db} Datomic: Yes! I think you got it. Let\u0026rsquo;s try one more.\nHuman: Ok. How about the dog\u0026rsquo;s favorite treat?\n{:db/id (d/tempid :db.part/db) :db/ident :dog/favorite-treat :db/valueType :db.type/string :db/cardinality :db.cardinality/one :db/doc \u0026#34;Dog\u0026#39;s Favorite Treat to Eat\u0026#34; :db.install/_attribute :db.part/db} Datomic: You got it. Now, that you have these attributes, you can give them to me using a transaction with the connection.\nHuman: Ok. Do you want that in a specific format?\nDatomic: Yes. Please send it to me using the form:\n(d/transact conn [....facts....]) Human: Sounds good. I will put the dog schema datoms we discussed in a vector and call it dog-schema and then send it to you.\n(def dog-schema [{:db/id (d/tempid :db.part/db) :db/ident :dog/name :db/valueType :db.type/string :db/cardinality :db.cardinality/one :db/unique :db.unique/identity :db/doc \u0026#34;Name of the Dog\u0026#34; :db.install/_attribute :db.part/db} {:db/id (d/tempid :db.part/db) :db/ident :dog/breed :db/valueType :db.type/string :db/cardinality :db.cardinality/one :db/doc \u0026#34;Breed of the Dog\u0026#34; :db.install/_attribute :db.part/db} {:db/id (d/tempid :db.part/db) :db/ident :dog/favorite-treat :db/valueType :db.type/string :db/cardinality :db.cardinality/one :db/doc \u0026#34;Dog\u0026#39;s Favorite Treat to Eat\u0026#34; :db.install/_attribute :db.part/db}]) (d/transact conn dog-schema) Datomic: The transaction was fine. I know all about those dog attributes now.\nHuman: I would like to also add a schema for owners for the dogs now. I think I know how to describe the name of the owner, but I don\u0026rsquo;t know how to express how the owner has dogs.\nDatomic: Ah. I that case you can specify the db:valueType as a ref type. This lets me know that it references another entity.\nHuman: Do I need to tell you that is a type of dog somehow?\nDatomic: No. I am pretty smart that way. I will figure it out once you try to tell me about some real entities. In fact, entities don\u0026rsquo;t have types. A ref attribute can reference any entity.\nHuman: Cool. Well, in that case, here is the owner schema. The owner has a name and some dogs.\n(def owner-schema [{:db/id (d/tempid :db.part/db) :db/ident :owner/name :db/valueType :db.type/string :db/cardinality :db.cardinality/one :db/unique :db.unique/identity :db/doc \u0026#34;Name of the Owner\u0026#34; :db.install/_attribute :db.part/db} {:db/id (d/tempid :db.part/db) :db/ident :owner/dogs :db/valueType :db.type/ref :db/cardinality :db.cardinality/many :db/doc \u0026#34;Dogs of the Owner\u0026#34; :db.install/_attribute :db.part/db}]) (d/transact conn owner-schema) Datomic: The transaction is fine. I now know about the attributes that dogs and owners have. Would you like to tell me some facts about specific dogs and owners?\nHuman: Yes. Bob is an owner. He has two dogs. Fluffy is a poodle whose favorite treat is cheese, and Fido is a mixed breed, whose favorite treat is a bone. Lucy is also an owner who has one dog named Tiny. Tiny is a Great Dane whose favorite treat is cheese.\nI am a bit confused how to represent the dogs of the owners. How do I do that?\nDatomic: That is easy, just nest the datoms for dogs under the :owner/dogs attribute. You just need to create datoms for them. Each dog or owner will by its own map. Use :db/id set to (d/tempid :db.part/user) so I can generate it for you. Then use each attribute from the schema as the key and let me know the value.\nHuman: Like this?\n(d/transact conn [{:db/id (d/tempid :db.part/user) :owner/name \u0026#34;Bob\u0026#34; :owner/dogs [{:db/id (d/tempid :db.part/user) :dog/name \u0026#34;Fluffy\u0026#34; :dog/breed \u0026#34;Poodle\u0026#34; :dog/favorite-treat \u0026#34;Cheese\u0026#34;} {:db/id (d/tempid :db.part/user) :dog/name \u0026#34;Fido\u0026#34; :dog/breed \u0026#34;Mix\u0026#34; :dog/favorite-treat \u0026#34;Bone\u0026#34;}]} {:db/id (d/tempid :db.part/user) :owner/name \u0026#34;Lucy\u0026#34; :owner/dogs [{:db/id (d/tempid :db.part/user) :dog/name \u0026#34;Tiny\u0026#34; :dog/breed \u0026#34;Great Dane\u0026#34; :dog/favorite-treat \u0026#34;Cheese\u0026#34;}]}]) Datomic: Exactly right. I now know the facts about Bob and Lucy and their dogs.\nHuman: Umm, how do I query you about the facts that your know? For example, how do I ask you about the dog named Tiny?\nDatomic: There are a couple a ways to inquire about facts I know. To find out about the attributes of a specific dog, or entity, I would recommend using d/pull. You can ask me in the form of this to get all the attributes for a given dog name. Note that this works since the dog name is a way to uniquely identify the dog:\n(d/pull (d/db conn) \u0026#39;[*] [:dog/name \u0026#34;Tiny\u0026#34;]) Human: What is the (d/db conn) all about?\nDatomic: That function returns the current database value of the connection. The facts I know change during time. Every time there is a transaction, I consider the time to be different and there is a new database value. The d/db function gives you the most recent value that I know about.\nHuman: I am assuming the [*] is a wildcard that means give me all the attributes for that dog?\nDatomic: Exactly right.\nHuman: Ok. Tell me about Tiny.\n(d/pull (d/db conn) \u0026#39;[*] [:dog/name \u0026#34;Tiny\u0026#34;]) Datomic:\n{:db/id 17592186045424 :dog/name \u0026#34;Tiny\u0026#34; :dog/breed \u0026#34;Great Dane\u0026#34; :dog/favorite-treat \u0026#34;Cheese\u0026#34;} Tiny is a Great Dane that has a favorite treat of Cheese.\nHuman: This is fun. What about more complicated questions. How do I ask about the name of the owner of the dog \u0026ldquo;Tiny\u0026rdquo;?\nDatomic: For that I would ask using the datalog query d/q. It uses logic to unify your query with all of my facts and give you the result. The query itself would be a vector with logic statements inside like:\n\u0026#39;[:find ?owner-name :where [?dog :dog/name \u0026#34;Tiny\u0026#34;] [?owner :owner/dogs ?dog] [?owner :owner/name ?owner-name]] Human: Whoa. What is the deal with those question marks?\nDatomic: The things with the question marks are considered as variables that we will unify to find the answer. For example, we are looking for something that we are going to call ?owner-name. I am going the use the following constraints with my facts to try to find the answer:\nThere is an entity that we are going to call ?dog that has the attribute :dog/name that is \u0026ldquo;Tiny\u0026rdquo; There is an entity that we are going to call ?owner that has an attribute :owner/dogs that is the same as the ?dog entity That same ?owner entity also has an attribute :owner/name that has the value ?owner-name Human: Alright, so when I ask for this query, do I need to give you a database value too?\nDatomic: Yes. They should have the form of:\n(d/q \u0026#39;[datalog-query] db-value) Remember, to get the current db value use (d/db conn).\nHuman: Ok. Here we go.\n(d/q \u0026#39;[:find ?owner-name :where [?dog :dog/name \u0026#34;Tiny\u0026#34;] [?owner :owner/dogs ?dog] [?owner :owner/name ?owner-name]] (d/db conn)) Datomic:\nThe answer is:\n#{[\u0026#34;Lucy\u0026#34;]} Human: What if I want to pass the dog name as a parameter? How do I communicate that to you?\nDatomic: You will need to use an in clause in the query like this:\n\u0026#39;[:find [blah] :in $ ?dog-name :where [blah]] The $ is shorthand for the database value and the ?dog-name is what you will pass in as a parameter in the query after the db-value.\nHuman: Like this?\n(d/q \u0026#39;[:find ?owner-name :in $ ?dog-name :where [?dog :dog/name ?dog-name] [?owner :owner/dogs ?dog] [?owner :owner/name ?owner-name]] (d/db conn) \u0026#34;Tiny\u0026#34;) Datomic: Exactly right. The answer is Lucy again.\n#{[\u0026#34;Lucy\u0026#34;]} Human: I think I am getting the hang of this! Another quick question. How would I go about asking you which dogs have cheese as their favorite treat? I would want the dog\u0026rsquo;s name and breed back.\nDatomic: You would simply construct another datalog query. This time I would recommend that you combine the pull syntax within the find part of the query. The pull syntax is great at selecting attributes from an entity. So the find part would look something like this:\n[(pull ?dog [:dog/name :dog/breed]) ...] This will return the attributes of the :dog/name and the :dog/breed. The three dots on the end will let me know that you want a collection returned, so I will give you back a simple vector with the entity attributes requested, instead of the set of vectors I normally give back.\nThe where section of the query is going to look for the ?dog entity that matches the :dog/favorite-treat attribute with \u0026ldquo;Cheese\u0026rdquo;.\n\u0026#39;[:find [(pull ?dog [:dog/name :dog/breed]) ...] :where [?dog :dog/favorite-treat \u0026#34;Cheese\u0026#34;]] Human: Then I put it together with the current database value in a d/q function?\n(d/q \u0026#39;[:find [(pull ?dog [:dog/name :dog/breed]) ...] :where [?dog :dog/favorite-treat \u0026#34;Cheese\u0026#34;]] (d/db conn)) Datomic: Yup. The answer is:\n[{:dog/name \u0026#34;Fluffy\u0026#34;, :dog/breed \u0026#34;Poodle\u0026#34;} {:dog/name \u0026#34;Tiny\u0026#34;, :dog/breed \u0026#34;Great Dane\u0026#34;}] Human: Thanks so much. I think I beginning to get the hang of schemas and queries. What other things do I need to know about you?\nDatomic: Well, you have just scratched the surface really. One of the most interesting things about me is that I never forget facts. You can add new facts, like Tiny\u0026rsquo;s favorite food is now hotdogs, but I won\u0026rsquo;t forget that he liked cheese at another point in time.\nHuman: That sounds really interesting. I think I need some tea and cookies before I delve into that. Let\u0026rsquo;s take a short break and talk again soon.\nDatomic: My pleasure. I look forward to it.\nSpecial thanks to Paul deGrandis for the conversation idea :)\n(P.S. Humans, there are some great Datomic Training Videos if you want to learn more)\n","permalink":"https://gigasquidsoftware.com/blog/2015/08/15/conversations-with-datomic/","summary":"\u003cp\u003e\u003cimg loading=\"lazy\" src=\"https://avatars0.githubusercontent.com/u/1478702?v=3\u0026s=200\"\u003e\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eHuman:\u003c/strong\u003e Hi \u003ca href=\"http://www.datomic.com/\"\u003eDatomic\u003c/a\u003e.   I have been hearing good things about you.  I would like to talk to you and get to know you.  Is that alright?\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eDatomic:\u003c/strong\u003e Sure!  I would be happy to talk with you.  What language would you like to converse in?\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eHuman:\u003c/strong\u003e  I like Clojure.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eDatomic:\u003c/strong\u003e  That is one of my favorites too.  You know how to setup a Leiningen project right?\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eHuman:\u003c/strong\u003e Oh yes.  What dependency should I use?\u003c/p\u003e","title":"Conversations with Datomic"},{"content":"\nSometimes I want to create something and I run into a limitation or constraint. It is at this point where I am tempted to give up and say that I just can\u0026rsquo;t do that.\nAt this time, I remember Maurice Sendak and the origins of Where the Wild Things Are. In this interview with Bill Moyers, he explains how the book was originally titled Where the Wild Horses Are, but he couldn\u0026rsquo;t draw horses.\nShe was this torrential woman, passionate woman, who could spot talent 10 miles away. I had no education. I did not go to art school. My drawing was so crude. I had shines on shoes like in Mutt \u0026rsquo;n\u0026rsquo; Jeff in Walt Disney. And she saw through that monstrous crudity and cultivated me, really made me grow up. And then, it was time to do my own picture book.\nAnd I came to her with a title that was \u0026ldquo;Where the Wild Horses Are.\u0026rdquo; And she just loved that. It was so poetic and evocative. And she gave me a contract based on \u0026ldquo;Where the Wild Horses Are.\u0026rdquo; And then, it turned out after some very few months to her chagrin and anger, I couldn\u0026rsquo;t draw horses. The whole book would have to be full of horses to make the book make sense.\nAnd when I tried a number of things, I remember the acid tones. She said, \u0026ldquo;Maurice, what can you draw?\u0026rdquo; Okay. Cause she was investing in a full color picture book. That was an enormous thing back then.\nAnd so, I thought well things, things.\nLimits or constraints cannot hold back creativity. But it can help mold it in surprising directions.\n","permalink":"https://gigasquidsoftware.com/blog/2015/05/30/wild-horses-things-and-creativity/","summary":"\u003cp\u003e\u003cimg loading=\"lazy\" src=\"https://nmbdesigner.files.wordpress.com/2012/05/where-the-wild-things-are-2.jpeg\"\u003e\u003c/p\u003e\n\u003cp\u003eSometimes I want to create something and I run into a limitation or\nconstraint. It is at this point where I am tempted to give up and say\nthat I just \u003cem\u003ecan\u0026rsquo;t\u003c/em\u003e do that.\u003c/p\u003e\n\u003cp\u003eAt this time,  I remember Maurice Sendak and the origins of \u003cem\u003eWhere\nthe Wild Things Are\u003c/em\u003e.  In this \u003ca href=\"http://www.pbs.org/now/arts/sendak.html\"\u003einterview with Bill Moyers\u003c/a\u003e, he explains\nhow the book was originally titled \u003cem\u003eWhere the Wild Horses Are\u003c/em\u003e, but he\ncouldn\u0026rsquo;t draw horses.\u003c/p\u003e","title":"Wild Horses, Things, and Creativity"},{"content":"I made it to that magical moment when the Clojure book I had been working on so long was published and I could actually hold it in my hand.\nIt was an immense project and I am very happy that it is finally done. Since then, I met some people that are interested in writing books as well. They asked if I had any insights or tips having gone through the process as a first time author. I have collected them in this post in hopes that they will be helpful to those going through the process themselves.\nThe very first thing to do is to get an outline for your book.\nStart with an Outline Ideas are soft and squishy. They drift into different shapes like clouds, and can melt away just as quickly. One of the hardest things to do was trying to arrange all those ideas in my head into an initial form that would serve as the structure for the entire book. I would pick up a pen and paper, start feeling overwhelmed, and suddenly remember I had something else very pressing to do. I successfully avoided starting a book for quite a while, until one day I cornered myself. I decided that I write my book outline on a long plane flight. With salted peanuts as fuel, and nowhere to escape, I finally wrote an outline. It wasn\u0026rsquo;t perfect but it was a start and looking back and it was not too far off. Here it is in all of its original roughness.\nTitle: Living Clojure From beginning steps to thriving in a functional world (Each Chapter will follow quotes from Alice in Wonderland and very use ideas from some examples) Book 1 - Beginner steps Chapter 1 - Are you comfortable? Talk about how OO is comfortable but there is another world out there and new way of thinking functionally. White Rabbit goes by Chapter 2 - Forms \u0026amp; Functions - Falling down the rabbit hole Chapter 3 - Functional Transformations - Growing bigger and smaller - Key to thinking functionally is about transforming data from one shape to another shape. Map \u0026amp; Reduce Chapter 4 - Embracing side effects - Clojure is impure functional language (The rabbit\u0026#39;s glove) - Cover do and io stuff. Also basic stuff about STM atoms and agents/ Protocols Chapter 5 - Libraries, Libraries - - how to use Leiningen build system. Where to find clojure libraries, how to use Serpents - camel-snake-kebab Chapter 6 - core.asyc - Tea Party introduction to the core.async library Chapter 7 - Clojure web - Chesire cat - introduction to Ring, Cheshire library, ClojureScript and OM Book 2 - From here to there - thriving in a functional world Training plan for thriving in a functional world. Chapter 8 - Join the community - Surround yourself with other Clojure enthusiats - Twitter clojure - Github account - Clojure mailing list - Prismatic clojure news - Meetup for local community group. If there is not one in your area. start one! - Attend a Clojure conj Chatpter 9 - Practice and build up Like Couch to 5K 7 week training program to work up to practicing Clojure Now that I had an outline. I just needed to figure out how long it would take me to write the book.\nHowever Long You Think It Will Take - You Are Wrong Having never written a book before, I had no idea how much work it would be. The closest thing I had to compare it to was writing a blog post. I figured writing a chapter would be roughly equivalent to writing a blog post. If I could go back in time, this is the moment where my future self would pour a glass of ice water on my past self. Writing a book is nothing like that. It is a lot of time and work. If I had to compare it now to writing blog posts, the process would be this.\n- You write a blog post. - You rewrite the blog post. - You write a second blog post. - You rewrite that blog post and the first one too. - You write another blog post. - You rewrite all three post ..... So, if you have to commit to deadlines, make sure you remember how hard it will be, and then double the number.\nSpeaking of deadlines, they suck, but you should have them.\nMake Deadlines Deadlines are not fun. In fact, deadlines might even be a source of potential panic. But for me, they were necessary evil. There were a few beautiful times when inspiration came knocking at my door and I couldn\u0026rsquo;t wait to start writing. But most of the time, inspiration was off somewhere else eating biscuits. The only thing that actually moved the book along was me knowing that I needed to get the next chunk done by a certain date.\nI found the best thing to do was to set aside a small bit of time on a daily basis to write something.\nRoutine, Routine, Routine A daily routine was the most crucial thing for me. Life is really busy with work and family. It is so easy to get overwhelmed with daily life. I decided that mornings would work best for me. So I would stumble in to my computer an hour before work, with a hot cup of tea in hand, and write something. Some days I actually did quite a bit. Other days, I would write one sentence and declare it done. But, I would always do something. Even though those small slices of time didn\u0026rsquo;t seem like a lot, they added up over the course of a week.\nAnother curious thing happens when you do something, even a little bit, day after day. You start to get better at it.\nWriting is a Different Skill from Coding I was used to writing code all day. I found that the code writing skills are not the same as writing about code. In fact, I found it really hard to do at the start. But, just like writing code, you get better with practice. And to get better at anything, feedback is really important.\nGet and Trust Feedback After each chapter, I would get feedback from my editor. She was awesome and provided ways for me to improve the experience for the reader. I lost track of how many times I rewrote that first chapter, but each time it would get a bit better and I would improve as well. After the book was about half done it was sent out to others for technical review. They provided feedback not only on the writing style but also the technical content, making sure that it all made sense.\nThe feedback loop is much slower for writing a book than writing code, but it is just as vital. The great people providing feedback are you closest partners in this. You need to trust them. Especially during the roughest time, the middle of the book.\nThe Middle Bit is the Hardest I found the hardest time was about halfway through the book. The initial excitement of the new endeavor had long since worn off. It seemed like such a mountain of a task, with no end in sight. I questioned my decision to continue with it daily. My routine and deadlines kept me moving forward. But my circle of friends and family kept me sane. It was great to have an outlet, not only to vent my frustration with my slow progress, but to get kind encouragement to keep my spirits up.\nDuring these dark days, I also ate cheese.\nCelebrate Your Small Victories At the end of every chapter or deadline I would fix myself a nice plate of cheese and crackers. You have to celebrate the small wins. Cheese is also very tasty.\nWhen the book was finally done. I had a really tasty plate, complete with Stilton, Brie, and a dependable Cheddar. I was incredibly happy to be finished. But I knew that I definitely could have not done it without the help of others.\nThank Everyone that Supported You Writing a book is a huge undertaking that is utterly impossible to do alone. I could have not done it without the help and support of my editor, reviewers, family, friends, as well as the entire Clojure Community. I am so thankful to all of you that helped my in this project. You are great.\nSo, should you go ahead and write that book?\nDo It Yes, you should write that book and share your knowledge. Don\u0026rsquo;t panic, remember to breathe, get some cheese and tea, and go for it! It will be awesome.\n","permalink":"https://gigasquidsoftware.com/blog/2015/05/22/how-not-to-panic-while-writing-a-clojure-book/","summary":"\u003cp\u003eI made it to that magical moment when the Clojure book I had been working on so long was published and I could actually hold it in my hand.\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"https://pbs.twimg.com/media/CDWsQPCUgAERViK.jpg\"\u003e\u003c/p\u003e\n\u003cp\u003eIt was an immense project and I am very happy that it is finally done.  Since then, I met some people that are interested in writing books as well.\nThey asked if I had any insights or tips having gone through the process as a first time author.  I have collected them in this post in hopes that they will be helpful to those going through the process themselves.\u003c/p\u003e","title":"How Not to Panic While Writing a Clojure Book"},{"content":"Clojure\u0026rsquo;s partition and partition-all functions are very useful. However, I have been bitten a few times using partition when I really wanted partition-all. So to help myself and all of you to remember it, I have made some diagrams with pugs from the Game of Thrones\nIn code, partition takes a collection and returns a lazy sequence of lists, each containing n items.\nTo demonstrate this with pugs, we will partition 5 pugs into groups of twos.\nThis partition will give you two groups of two pugs.\nNotice, (and here is the important part), the last pug is missing. The Joffrey pug is not included because partition will not include items that do not make a complete partition. In this case, because there is no group of 2 pugs for the Joffrey pug to be in, it gets dropped.\nThis is the thing that has bitten me in the past.\nA common use for wanting to partition things is to control the number of things that you process at one time. An example of this is sending only 500 items to be processed in a batch job at one time. If you have a few thousand items to be processed, partitioning them is a good way of chuncking. However, if you have an arbitrary number of items, you most certainly want to process them all and not drop any. This is where you should use partition-all instead.\nPartition-all chunks the items as well, but also includes any leftovers. Demonstrating again with pugs.\nThis partition-all will give you three groups of pugs.\nThis time pug Joffrey is not left out!\nRemember, think carefully before using partition. Don\u0026rsquo;t leave a pug out.\nBy the way, I can\u0026rsquo;t wait till the next season of Game of Thrones. Until then ..\n","permalink":"https://gigasquidsoftware.com/blog/2015/01/26/partition-with-game-of-thrones-pugs/","summary":"\u003cp\u003eClojure\u0026rsquo;s \u003cem\u003epartition\u003c/em\u003e and \u003cem\u003epartition-all\u003c/em\u003e functions are very useful.\nHowever, I have been bitten a few times using \u003cem\u003epartition\u003c/em\u003e when I\nreally wanted \u003cem\u003epartition-all\u003c/em\u003e.  So to help myself and all of you to\nremember it, I have made some diagrams with \u003ca href=\"http://www.designswan.com/archives/the-pugs-of-westeros-cute-pugs-dressed-up-like-characters-in-game-of-thrones.html\"\u003epugs from the Game of Thrones\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003eIn code, \u003ca href=\"http://clojuredocs.org/clojure.core/partition\"\u003epartition\u003c/a\u003e takes a collection and returns a lazy sequence of\nlists, each containing n items.\u003c/p\u003e\n\u003cp\u003eTo demonstrate this with pugs, we will partition 5 pugs into groups of\ntwos.\u003c/p\u003e","title":"Partition with Game of Thrones Pugs"},{"content":"\nIt\u0026rsquo;s that time of year for radars to be published. So this year, I thought I would publish one of my own. Here is what is on my radar.\nLanguages Adopt: Clojure - It is fantastic language. Really. Trial: Pixie - The promise of a really fast startup Clojure inspired language. I am impressed already and it is only a few months old. Assess: Idris - I have only seen this lang briefly, but was impressed by the typing and proofing abilities. Hold: JavaScript - I don\u0026rsquo;t have to say more, you know what I mean. Cute Animals Adopt: Llamas Trial: Alpacas Assess: Wombats Hold: Hedgehogs Robots Adopt: Parrot AR Drone Hackable flying drone with sonar and cameras. Doesn\u0026rsquo;t injure your fingers too much when you get them caught in the blades. Trial: PhantomX Hexapod A bit pricey and delicate, but built from kit and is super cool when you get it going. Assess: Myo Armband Control things with a flick of your wrist. Mine finally arrived after a year and a half wait. I haven\u0026rsquo;t had time to play with it, but I have high hopes for it. Hold: Roombas - I love my Roombas, but I am not sure the latest models have an ROI port to hack :( Tasty Food Adopt: Crumpets - Put lots of butter on them toasted. Yum! Trial: Mint Tim Tams- Minty, just the right amount of crunch. Hard to find in the US, but a treat when you do. Assess: Raclette - I have never actually had it, but it is melted cheese, it has to be incredible. Hold: Egg Nog - Don\u0026rsquo;t drink it directly from the bowl. Happy Holidays Everyone!\n","permalink":"https://gigasquidsoftware.com/blog/2014/12/17/gigasquids-radar-2014/","summary":"\u003cp\u003e\u003cimg loading=\"lazy\" src=\"https://c4.staticflickr.com/8/7554/16045999682_b4658620c1_c.jpg\"\u003e\u003c/p\u003e\n\u003cp\u003eIt\u0026rsquo;s that time of year for \u003cem\u003eradars\u003c/em\u003e to be published.  So this year, I thought I would publish one of my own. Here is what is on my radar.\u003c/p\u003e\n\u003ch2 id=\"languages\"\u003eLanguages\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cem\u003eAdopt\u003c/em\u003e: Clojure - It is fantastic language. Really.\u003c/li\u003e\n\u003cli\u003e\u003cem\u003eTrial\u003c/em\u003e: \u003ca href=\"https://github.com/pixie-lang/pixie\"\u003ePixie\u003c/a\u003e - The promise of a really fast startup Clojure inspired language.  I am impressed already and it is only a few months old.\u003c/li\u003e\n\u003cli\u003e\u003cem\u003eAssess\u003c/em\u003e: \u003ca href=\"http://www.idris-lang.org/\"\u003eIdris\u003c/a\u003e - I have only seen this lang briefly, but was impressed by the typing and proofing abilities.\u003c/li\u003e\n\u003cli\u003e\u003cem\u003eHold\u003c/em\u003e: JavaScript - I don\u0026rsquo;t have to say more, you know what I mean.\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"cute-animals\"\u003eCute Animals\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cem\u003eAdopt\u003c/em\u003e: \u003ca href=\"http://www.llamas.org/imgs/corner.jpg\"\u003eLlamas\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003cem\u003eTrial\u003c/em\u003e: \u003ca href=\"http://www.preciousanimals.com/wp-content/plugins/woo-tumblog/functions/thumb.php?src=wp-content/uploads/2012/03/Cute-Animals-4e41e26ba45d7.jpg\u0026amp;w=530\u0026amp;h=\u0026amp;zc=1\u0026amp;q=90\"\u003eAlpacas\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003cem\u003eAssess\u003c/em\u003e: \u003ca href=\"http://i.dailymail.co.uk/i/pix/2014/08/27/article-0-20D869FB00000578-191_634x758.jpg\"\u003eWombats\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003cem\u003eHold\u003c/em\u003e: \u003ca href=\"http://4.bp.blogspot.com/-expAkvezlsw/UjJIGE3EqMI/AAAAAAAABoo/UcCeUo7ALtc/s1600/cute-hedgehog-dino-toy.jpg\"\u003eHedgehogs\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"robots\"\u003eRobots\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cem\u003eAdopt\u003c/em\u003e: \u003ca href=\"http://ardrone2.parrot.com/\"\u003eParrot AR Drone\u003c/a\u003e Hackable flying drone with sonar and cameras. Doesn\u0026rsquo;t injure your fingers too much when you get them caught in the blades.\u003c/li\u003e\n\u003cli\u003e\u003cem\u003eTrial\u003c/em\u003e: \u003ca href=\"http://gigasquidsoftware.com/blog/2014/03/20/world-domination-with-hexapods-and-clojure/\"\u003ePhantomX Hexapod\u003c/a\u003e A bit pricey and delicate, but built from kit and is super cool when you get it going.\u003c/li\u003e\n\u003cli\u003e\u003cem\u003eAssess\u003c/em\u003e: \u003ca href=\"https://www.thalmic.com/en/myo/\"\u003eMyo Armband\u003c/a\u003e Control things with a flick of your wrist.  Mine finally arrived after a year and a half wait.  I haven\u0026rsquo;t had time to play with it, but I have high hopes for it.\u003c/li\u003e\n\u003cli\u003e\u003cem\u003eHold\u003c/em\u003e: Roombas - I love my Roombas, but I am not sure the latest models have an ROI port to hack :(\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"tasty-food\"\u003eTasty Food\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cem\u003eAdopt\u003c/em\u003e: \u003ca href=\"http://upload.wikimedia.org/wikipedia/commons/3/38/Buttered_crumpet2.jpg\"\u003eCrumpets\u003c/a\u003e - Put lots of butter on them toasted. Yum!\u003c/li\u003e\n\u003cli\u003e\u003cem\u003eTrial\u003c/em\u003e: \u003ca href=\"http://www.aussiefoodshop.com/i/peppe%20biscuits/dark_choc_mint.JPG\"\u003eMint Tim Tams\u003c/a\u003e-  Minty, just the right amount of crunch. Hard to find in the US, but a treat when you do.\u003c/li\u003e\n\u003cli\u003e\u003cem\u003eAssess\u003c/em\u003e: \u003ca href=\"http://en.wikipedia.org/wiki/Raclette\"\u003eRaclette\u003c/a\u003e - I have never actually had it, but it is melted cheese, it has to be incredible.\u003c/li\u003e\n\u003cli\u003e\u003cem\u003eHold\u003c/em\u003e: Egg Nog - Don\u0026rsquo;t drink it directly from the bowl.\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eHappy Holidays Everyone!\u003c/p\u003e","title":"Gigasquid's Radar 2014"},{"content":"\nSure you may have done FizzBuzz before. Maybe you have even done it in Clojure. But have you done it without the use of any conditionals?\nAs your brain starts to work on the how this we be done, you might be wondering why you should do this in the first place?\nThere are two very good reasons for this. The first is that it is a kata.\nKatas build your code practice Code katas build your skill through practice. It doesn\u0026rsquo;t matter if you are a beginner or an expert. Just, like in all those martial arts movies with the swordsman practicing, so must we. We stretch and flex our coding muscles with katas to grow them and keep them in shape.\nYes, you may code every day at work. But it is not the same as kata practice. So much of day to day work involves complexity with large interconnected concerns. Our kata practice cuts the extra complexity out and leaves you alone with a focused small problem.\nThe second reason involves why you should try it, this time, without conditionals. The answer is creativity.\nConstraints build creativity. It turns out that constraints are a key way to drive creativity. Programming does not only require technical skills, but also creativity. We are seldom asked to build software without constraints. It drives design. Sure, it can be annoying when we have to communicate with a server that is only active on Tuesday and emits its response in Morse Code. But it gives us boundaries to unleash our creative spirit.\nSo go for it.\nGive it a try Ready? Here are the details.\nGiven a number, if it number is divisible by 3 return \u0026ldquo;fizz\u0026rdquo;. If it is divisible by 5 return \u0026ldquo;buzz\u0026rdquo;. If it is divisible by 3 and 5 return \u0026ldquo;fizzbuzz\u0026rdquo;. Otherwise, just return the number. Don\u0026rsquo;t use any conditionals like if else case cond. When you are done, you can check out some of the other solutions. Try not to peek until you have done your version first though.\n(There are some really awesome ones so far).\nFeel free to link to yours in the comments too :)\nSolutions From @aderth\nFrom @IamDrowsy\nFrom @Bryanwoods\nFrom @defndaines\nFrom me\nFrom @hyPiRion - a couple of notes for this one is that:\n(+) ;; -\u0026gt; 0 and\n(*) ;; -\u0026gt; 1 And once you think about that, you might want to read this :)\nHappy Clojure Kataing!\n","permalink":"https://gigasquidsoftware.com/blog/2014/11/13/clojure-fizzbuzz-without-conditionals/","summary":"\u003cp\u003e\u003cimg loading=\"lazy\" src=\"https://c1.staticflickr.com/5/4136/4825113119_9630b7927f.jpg\"\u003e\u003c/p\u003e\n\u003cp\u003eSure you may have done FizzBuzz before.  Maybe you have even done it\nin Clojure.  But have you done it without the use of \u003cem\u003eany\u003c/em\u003e\nconditionals?\u003c/p\u003e\n\u003cp\u003eAs your brain starts to work on the \u003cem\u003ehow\u003c/em\u003e this we be done, you might\nbe wondering \u003cem\u003ewhy\u003c/em\u003e you should do this in the first place?\u003c/p\u003e\n\u003cp\u003eThere are two very good reasons for this.  The first is that it is a\n\u003cem\u003ekata\u003c/em\u003e.\u003c/p\u003e\n\u003ch2 id=\"katas-build-your-code-practice\"\u003eKatas build your code practice\u003c/h2\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"https://c4.staticflickr.com/4/3552/3434757877_711709da58_b.jpg\"\u003e\u003c/p\u003e","title":"Clojure FizzBuzz without Conditionals"},{"content":"\nDenial: I am not really writing a book. Anger: Why did I ever decide to write a book? Bargaining: If I just finish this book, I promise never to write another one. Depression: I am never going to finish this book. Resolution: I am writing a book and I am going to give it my frigging all. ","permalink":"https://gigasquidsoftware.com/blog/2014/11/10/the-five-stages-of-writing-a-book/","summary":"\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/images/posts/6ab5e842-8314929977_28fd740070_c.jpg\"\u003e\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e\u003cem\u003eDenial\u003c/em\u003e: I am not really writing a book.\u003c/li\u003e\n\u003cli\u003e\u003cem\u003eAnger\u003c/em\u003e: Why did I ever decide to write a book?\u003c/li\u003e\n\u003cli\u003e\u003cem\u003eBargaining\u003c/em\u003e: If I just finish this book, I promise never to write another one.\u003c/li\u003e\n\u003cli\u003e\u003cem\u003eDepression\u003c/em\u003e: I am never going to finish this book.\u003c/li\u003e\n\u003cli\u003e\u003cem\u003eResolution\u003c/em\u003e: I am writing a book and I am going to give it my \u003cem\u003efrigging all\u003c/em\u003e.\u003c/li\u003e\n\u003c/ol\u003e","title":"The Five Stages of Writing a Book"},{"content":"\nRecently, I switched from a traditional, \u0026ldquo;go to an office\u0026rdquo; job, to working from my home. It took some time to setup my home work space and get used to working remotely, but I finally have a system working for me. In this post, I thought I would share some things that I found useful.\nWindow Seat Please If at all possible, locate your home work space near a window. The natural light does wonders for you mood and being able to glance up and look at trees and real life is a refreshing break from staring at code all day.\nA Door is Great Having a door to your workspace is a real advantage. It enables you to close off noise and other activity that might be going on in the house. It is also incredibly useful if you have small children. For my kids, if the door is closed, then it is a sign that Mommy is working - do not disturb.\nInvest in a good chair. Backs are very important. I started working from home with just my kitchen chair - big mistake. After a day or two, my back was crying out for something better. I did some research on good chairs to get and I ended up with a Steelcase Leap Chair. They are not cheap. But, I was able to get a refurb one that was considerably less than new, and my back loves it.\nDon\u0026rsquo;t Sit All the Time Even with my great chair, it is not the best to sit constantly. I had tried a straight standing desk a while back and I found that standing all the time was not the best for me. I prefer to mix it up. I got a adjustable Geek Desk. I generally stand up in the morning and sit in the afternoons.\nFreedom from a Headset with a Good Mic I have used a headset before when doing remote calls. They work fine, but after a while, I found it annoying to have on my head all day. I switched to a Blue Snowball Mic at home and am really happy with it. My voice comes in clear and I am headset free.\nDual Monitors for the Win I use two Thunderbolt displays. One monitor I use for communications, it has my email, chat, and video on it. The other monitor I use for the codez. It works out pretty well to switch back and forth.\nGood Software for Communication Good communication is a must for working remotely. Someone cannot just wander over to your desk and ask you a question. Here is a list of communication tools I use at work:\nSlack - for team communication. Google Docs Zoom - for video and screen sharing. It is way better than Google hangouts in terms of video quality. Apple\u0026rsquo;s Screen sharing - for pair code development. This let\u0026rsquo;s people use whatever editor they are comfortable with, yet you can see the code and still share control. Pair Programming is Awesome At work, we do pair programming most of the time. I really like to work this way. One of the things that I was concerned about in switching to remote work was being lonely. Pair programming really helps in this. I am usually working with someone during the day, with one monitor going with video and voice, while the other monitor has the code we are working on. For me, it has all the advantages of idea sharing and group problem solving. I realize that working this way is not for everyone, but I am digging it.\nRoutine is Everything When working for home, I have found it is crucial to have a good routine. Since we do a lot of pair programming at work, we all generally keep the same hours. Being a distributed team over North America, this means I start work at around 10am EST. I have found that having a routine a sticking to it helps structure my day. I get up, get dressed, eat breakfast, just like I was going to work. Then, I usually hack for a bit on personal stuff in the morning until it is time for work. Then at lunch, I go for a run or work out. Finally, and most importantly, in the evening, I leave the computer behind and devote time to family.\nDon\u0026rsquo;t Forget to Visit with Other Humans The downside of working from home is that it is very easy to not leave home. At one point, I realized that I had not left the house for a week. Not good. I try go to a social event where I will meet with other developers and friends every week. There is a nice developer coffee group that meets on Fridays. I also help run our Cincinnati Functional Programmer\u0026rsquo;s Group here in town. In general, I find that if I am driving somewhere and see people walking on the street and start thinking, \u0026ldquo;Look Humans!\u0026rdquo;, it is time to get out and socialize a bit more. Working remotely, makes going to conferences and being with other developers in person even more fun.\nSummary (with a Dog Pic) I have found working remotely to be quite enjoyable so far. It does take an extra effort to keep your life structured and communication flowing properly, but it is worth it.\nMy next challenge, since it is getting colder, is to get my dog to sleep on my feet while I work. No luck so far.\nIf anyone has any tips, let me know.\n","permalink":"https://gigasquidsoftware.com/blog/2014/10/31/notes-and-tips-on-working-from-home/","summary":"\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/images/posts/d99e385e-15671394561_261bf74b95.jpg\"\u003e\u003c/p\u003e\n\u003cp\u003eRecently, I switched from a traditional, \u0026ldquo;go to an office\u0026rdquo;\njob,\nto working from my home.  It took some time to setup my home\nwork space and get used to working remotely, but I finally have a\nsystem working for me.  In this post, I thought I would share some things that I\nfound useful.\u003c/p\u003e\n\u003ch3 id=\"window-seat-please\"\u003eWindow Seat Please\u003c/h3\u003e\n\u003cp\u003eIf at all possible, locate your home work space near a window.  The\nnatural light does wonders for you mood and being able to glance up\nand look at trees and real life is a refreshing break from staring at\ncode all day.\u003c/p\u003e","title":"Notes and Tips on Working from Home"},{"content":"\nA quick tour of Clojure Transducers with core.async with Dr. Seuss as a guide.\nFollow along at home by:\nlein new green-eggs modify your project.clj to include the following: (defproject green-eggs \u0026#34;0.1.0-SNAPSHOT\u0026#34; :description \u0026#34;try them\u0026#34; :url \u0026#34;http://en.wikipedia.org/wiki/Green_Eggs_and_Ham\u0026#34; :license {:name \u0026#34;Eclipse Public License\u0026#34; :url \u0026#34;http://www.eclipse.org/legal/epl-v10.html\u0026#34;} :dependencies [[org.clojure/clojure \u0026#34;1.7.0-alpha1\u0026#34;] [org.clojure/core.async \u0026#34;0.1.338.0-5c5012-alpha\u0026#34;]]) Start up a repl and hack in! Green Eggs and Ham Transducers are a new feature of Clojure 1.7. Instead of trying to explain them with words, let\u0026rsquo;s take a look of them in action. First we need some data. Let\u0026rsquo;s def a vector of all the places you could try green eggs and ham.\n(ns green-eggs.core (:require [clojure.core.async :as async])) (def green-eggs-n-ham [\u0026#34;in the rain\u0026#34; \u0026#34;on a train\u0026#34; \u0026#34;in a box\u0026#34; \u0026#34;with a fox\u0026#34; \u0026#34;in a house\u0026#34; \u0026#34;with a mouse\u0026#34; \u0026#34;here or there\u0026#34; \u0026#34;anywhere\u0026#34;]) Next, let\u0026rsquo;s create a function that will transform the places into a \u0026ldquo;I would not eat them \u0026hellip;\u0026rdquo; sentence.\n(defn i-do-not-like-them [s] (format \u0026#34;I would not eat them %s.\u0026#34; s)) (i-do-not-like-them \u0026#34;in the rain\u0026#34;) ;; -\u0026gt; \u0026#34;I would not eat them in the rain.\u0026#34; We also need a function to take this result and actually try the green eggs and ham.\n(defn try-them [s] (clojure.string/replace s #\u0026#34; not\u0026#34; \u0026#34;\u0026#34;)) (try-them \u0026#34;I would not eat them in the rain.\u0026#34;) ;; -\u0026gt; \u0026#34;I would eat them in the rain.\u0026#34; Now we have two transformations that we can apply to the vector of green-eggs-n-ham strings. One of the really nice things about transducers is that you can describe and compose this transformation without a data structure present.\n(def sam-i-am-xform (comp (map i-do-not-like-them) (map try-them))) We can run the transformation of the transducers against the data in a few ways.\ninto: Non-lazy turn the transformation into a collection sequence: Same thing but lazy transduce: Acts like reduce on the all the transformed elements With core.async channels doing the transformations. Let\u0026rsquo;s look at the green eggs and ham example for each one of these ways:\nInto Into takes a transducer and collection to work on and returns the vector we asked for:\n(into [] sam-i-am-xform green-eggs-n-ham) ;; -\u0026gt; [\u0026#34;I would eat them in the rain.\u0026#34; ;; \u0026#34;I would eat them on a train.\u0026#34; ;; \u0026#34;I would eat them in a box.\u0026#34; ;; \u0026#34;I would eat them with a fox.\u0026#34; ;; \u0026#34;I would eat them in a house.\u0026#34; ;; \u0026#34;I would eat them with a mouse.\u0026#34; ;; \u0026#34;I would eat them here or there.\u0026#34; ;; \u0026#34;I would eat them anywhere.\u0026#34;] Sequence Sequence takes similar arguments, but as promised, returns a lazy sequence that we can interact with.\n(class (sequence sam-i-am-xform green-eggs-n-ham)) ;; -\u0026gt; clojure.lang.LazyTransformer (take 1 (sequence sam-i-am-xform green-eggs-n-ham)) ;; -\u0026gt; (\u0026#34;I would eat them in the rain.\u0026#34;) Transduce If we want to finally arrange all our sentences in the vectors into one string, we would use reduce. The way to do this with transducers is to use transduce. It takes a function of two arguments to perform the reduce, as well as an initial data input.\n(transduce sam-i-am-xform #(str %1 %2 \u0026#34; \u0026#34;) \u0026#34;\u0026#34; green-eggs-n-ham) ;; -\u0026gt; \u0026#34;I would eat them in the rain. ;; I would eat them on a train. ;; I would eat them in a box. ;; I would eat them with a fox. ;; I would eat them in a house. ;; I would eat them with a mouse. ;; I would eat them here or there. ;; I would eat them anywhere.\u0026#34; ;;_note: In 1.7.0-alpha2, transduce changed and you need to use a ;;(transduce sam-i-am-xform (completing #(str %1 %2 \u0026#34; \u0026#34;)) \u0026#34;\u0026#34; green-eggs-n-ham) ;;instead. Core.async Core.async has a really nice way to define channels with a transducer that will transform each element on the channel.\n(def sam-i-am-chan (async/chan 1 sam-i-am-xform)) Let\u0026rsquo;s define another channel to reduce the results of the sam-i-am-chan to a string.\n(def result-chan (async/reduce #(str %1 %2 \u0026#34; \u0026#34;) \u0026#34;\u0026#34; sam-i-am-chan)) Finally, let\u0026rsquo;s actually put the green-eggs-n-ham data onto the sam-i-am-chan and let the data transformations flow\u0026hellip;.\n(async/onto-chan sam-i-am-chan green-eggs-n-ham) At last, we can get our result off the result channel and revel in the beauty of asynchronous data transducers.\n(def i-like-them (async/\u0026lt;!! result-chan)) i-like-them ;; -\u0026gt; \u0026#34;I would eat them in the rain. ;; I would eat them on a train. ;; I would eat them in a box. ;; I would eat them with a fox. ;; I would eat them in a house. ;; I would eat them with a mouse. ;; I would eat them here or there. ;; I would eat them anywhere.\u0026#34; Transducers are elegant and powerful, just like the rest of Clojure. Try them, you will like them :)\n","permalink":"https://gigasquidsoftware.com/blog/2014/09/06/green-eggs-and-transducers/","summary":"\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://upload.wikimedia.org/wikipedia/en/c/c2/Greenegg.gif\"\u003e\u003c/p\u003e\n\u003cp\u003eA quick tour of Clojure Transducers with core.async with Dr. Seuss as a guide.\u003c/p\u003e\n\u003cp\u003eFollow along at home by:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ccode\u003elein new green-eggs\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003emodify your project.clj to include the following:\u003c/li\u003e\n\u003c/ul\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-clojure\" data-lang=\"clojure\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e(\u003cspan style=\"color:#66d9ef\"\u003edefproject \u003c/span\u003egreen-eggs \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;0.1.0-SNAPSHOT\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#e6db74\"\u003e:description\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;try them\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#e6db74\"\u003e:url\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;http://en.wikipedia.org/wiki/Green_Eggs_and_Ham\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#e6db74\"\u003e:license\u003c/span\u003e {\u003cspan style=\"color:#e6db74\"\u003e:name\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Eclipse Public License\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#e6db74\"\u003e:url\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;http://www.eclipse.org/legal/epl-v10.html\u0026#34;\u003c/span\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#e6db74\"\u003e:dependencies\u003c/span\u003e [[org.clojure/clojure \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;1.7.0-alpha1\u0026#34;\u003c/span\u003e]\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                 [org.clojure/core.async \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;0.1.338.0-5c5012-alpha\u0026#34;\u003c/span\u003e]])\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cul\u003e\n\u003cli\u003eStart up a repl and hack in!\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"green-eggs-and-ham\"\u003eGreen Eggs and Ham\u003c/h2\u003e\n\u003cp\u003eTransducers are a new feature of Clojure 1.7.  Instead of trying to explain them with words, let\u0026rsquo;s take a look of them in action.  First we need some data.  Let\u0026rsquo;s def a vector of all the places you could try green eggs and ham.\u003c/p\u003e","title":"Green Eggs and Transducers"},{"content":"Sometimes I pause before talking to someone about Clojure code. Not because I am unsure of the code, but because I am unsure of how to pronounce the code. The particular code in question is Clojure\u0026rsquo;s assoc. I have heard it pronounced two ways. One is \u0026ldquo;assosh\u0026rdquo;, the other is \u0026ldquo;assok\u0026rdquo;. So, to determine it, I decided to conduct a scientific poll of the Clojure community.\nI posted the poll on twitter to the Cojure community who follow me. The control group poll was not viewed by those who do not follow me, and/or, are not on twitter.\nThe results were startling.\nassosh - 10 assok - 8 assose - 2 Jeremy - 1 asoaksh - 1 The community is clearly deeply divided on this important question.\nAfter sifting through the raw data, I remembered my statistical analysis and threw out the extremes.\nThe conclusion was still a stark reality.\nWe do not as a community know how to pronounce assoc.\nSolution I can only see one way forward. We must address this as a community. I propose that the community documentation of Clojure Docs and Grimoire modify their sites to include audio pronunciation like this.\nRemember, I\u0026rsquo;m pulling for you. We are all in this together.\n","permalink":"https://gigasquidsoftware.com/blog/2014/07/28/the-proper-pronunciation-of-clojures-assoc/","summary":"\u003cp\u003eSometimes I pause before talking to someone about Clojure code. Not because I am unsure of the code, but because I am unsure of\nhow to pronounce the code.  The particular code in question is\nClojure\u0026rsquo;s \u003cem\u003eassoc\u003c/em\u003e.  I have heard it pronounced two ways. One is\n\u0026ldquo;assosh\u0026rdquo;, the other is \u0026ldquo;assok\u0026rdquo;.  So, to determine it, I decided to conduct a\nscientific poll of the Clojure community.\u003c/p\u003e\n\u003cp\u003eI posted the poll on\n\u003ca href=\"https://twitter.com/gigasquid/status/493891057906896896\"\u003etwitter\u003c/a\u003e to\nthe Cojure community who follow me.  The control group poll was not viewed\nby those who do not follow me, and/or, are not on twitter.\u003c/p\u003e","title":"The Proper Pronunciation of Clojure's Assoc"},{"content":"\nNobody knows how it happened. Some people think it was due to the rapid expansion and adoption of Clojure. Other people say that the language itself was caused by something deeper and more magical. No one knows for sure. All that we really know is that people starting being born with extraordinary powers. Powers that no human had had before. They were strange and unique to each person they touched. The only thing that they all had in common, was that each was an aspect of the Clojure programming language.\nLuke (AKA Lazy Luke) Luke was a teenager when his powers came to him. His mother always complained that he was lazy. It was true, he did prefer to sleep until noon. He also had a habit of putting everything off to the last minute, like saving all his papers for the night before they were due. One day, though, he noticed something very strange. He could start to see the future. Well not really “see” it. But he could see the infinite possibilities of the future. Not very far into the future, but enough. It was a few milliseconds at first. But now it was up to a full second. He checked the Clojure Docs as soon as he realized his gift. It was lazy evaluation and power to deal with infinite sequences.\nSpress Spress, whose real name is Emily, came into her power early. She was only 5 years old. Her mother had taken her to a farm to visit with the animals. Her mother had pointed at the cow and told her daughter that it said “Moo”. Then, at the horse, saying “Neigh”. Spress smiled and pointed at a bucket and said “cow”. Her mother shook her head at her, but Spress only smiled bigger. She said “cow” again. Then, suddenly, the bucket went “Moo”. She was immediately taken to the Clojure X-Men school, where they identified her power as protocols. She trained her power and now is so good at solving the “expression problem”, she is known as “Spress”.\nMulti Nobody knows Multi’s background. He came to notice in his early twenties with his powers. Ordinary humans process sensory input, (like sight, touch, and sound), in an asynchronous fashion. However, when it gets processed in the brain, it runs into a single pipeline bottleneck - consciousness. Multi’s power is that he can concurrently process his higher level consciousness and reasoning to all this sensory input. The result is that he can move, think, and perform super fast and in a super smart way. He got the power of Clojure’s concurrency.\nDot Dot always had a way with animals. She had many pets growing up. Later, she would go into the forest and the animals would seek her out. She would be found resting by a tree surrounded by deer and birds. One time, on her walk, she fell down a ditch and had her leg trapped under a log. Her mother arrived, after searching for her, to see a Bear reach down and gently remove the log. She stood dumbfounded, as her daughter thanked the bear and it nodded in reply as it turned away. She could talk with animals effortlessly. She had the power of Clojure’s Interop.\nBob Bob is the leader of the Clojure X-Men. He seeks out people with the power of Clojure and helps train and educate them. He also is the most powerful. He can come into any argument, problem, or challenge and immediately separate out what is most important to focus on. He always knows the right thing to do, without getting bogged down in unnecessary details . His power is Clojure’s simplicity.\nThere might be others out there, we don’t know. We can only hope, that they are found by Bob and the Clojure X-Men and use their powers for good.\n","permalink":"https://gigasquidsoftware.com/blog/2014/07/27/clojure-x-men/","summary":"\u003cp\u003e\u003cimg loading=\"lazy\" src=\"https://c2.staticflickr.com/6/5557/14761955842_6a8bf4a66a_n.jpg\"\u003e\u003c/p\u003e\n\u003cp\u003eNobody knows how it happened.  Some people think it was due to the rapid expansion and adoption of Clojure.  Other people say that the language itself was caused by something deeper and more magical.  No one knows for sure.  All that we really know is that people starting being born with extraordinary powers.  Powers that no human had had before.  They were strange and unique to each person they touched.  The only thing that they all had in common, was that each was an aspect of the Clojure programming language.\u003c/p\u003e","title":"Clojure X-Men"},{"content":"\nThe Earliest Known Love Song The earliest known love song was found in an Egyptian tomb. The fragment found in the 4,300 year old tomb read:\nI love and admire your beauty. I am under it. Medieval Love Songs Moving forward in history to Medieval times, there are many examples of love songs. One of them from a great composer in the 14th century, named Guillaume de Machaut:, went something like this:\nYou are the true sapphire that can heal and end all my sufferings, the emerald which brings rejoicing, the ruby to brighten and comfort the heart. Love Songs from this Summer Love songs abound on the radio and internet today. One was released by Coldplay recently, called \u0026ldquo;A Sky Full of Stars\u0026rdquo;. The lyrics go something like this:\nCause you're a sky Cause you're a sky full of stars I'm going to give you my heart Cause you're a sky Cause you're a sky full of stars And cause you light up the path Why Create? I have nothing to say that has not been said These are the whispering excuses that I hear in the back of my head when I sit down at a blank text editor:\nSomeone has already said this. Someone has already built this algorithm. Someone has already built this library. I have nothing to say that has not been said before. But it has not been said by you. Love is a universal human emotion. We have evidence that people have been writing about it and singing about it for at least 4,000 years.\nHasn\u0026rsquo;t everything already been said about it?\nNo.\nWe still want to hear it again. We still want to hear it new, said by another. It means something slightly different, feels different when said again by someone else with different experiences, from a different life, from a different perspective..\nThe same goes for your writing, your code, your library, and your creation.\nSo open up your favorite editor and brush aside your fears. It is a blank canvas, ready for your thoughts and code.\nSay it loud\nSay it strong\nCreate\nDon\u0026rsquo;t worry if it has been said before\nIt is new because it is said by you\n","permalink":"https://gigasquidsoftware.com/blog/2014/07/06/love-songs-through-history-and-why-you-should-create/","summary":"\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/images/posts/817554ca-lovesong.gif\"\u003e\u003c/p\u003e\n\u003ch2 id=\"the-earliest-known-love-song\"\u003eThe Earliest Known Love Song\u003c/h2\u003e\n\u003cp\u003eThe earliest known love song was found in an \u003ca href=\"http://news.nationalgeographic.com/news/2001/02/0213_1stlovesong.html\"\u003eEgyptian tomb\u003c/a\u003e.  The\nfragment found in the 4,300 year old tomb read:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003eI love and admire your beauty. I am under it.\n\u003c/code\u003e\u003c/pre\u003e\n\u003ch2 id=\"medieval-love-songs\"\u003eMedieval Love Songs\u003c/h2\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/images/posts/31a6d86f-manasseh.jpg\"\u003e\u003c/p\u003e\n\u003cp\u003eMoving forward in history to Medieval times, there are many examples\nof love songs. One of them from a great composer in the 14th century,\nnamed \u003ca href=\"http://public.wsu.edu/~brians/love-in-the-arts/medieval.html\"\u003eGuillaume de Machaut\u003c/a\u003e:, went something like\nthis:\u003c/p\u003e","title":"Love Songs Through History and Why You Should Create"},{"content":"A while ago, I was exploring creating a programming language with Instaparse. I ended up exploring some concepts of Speech Acts proposed by John McCarthy by creating my first toy language called Babar. Shortly after posting a blog about it, I got an email from someone saying that I might be interested in a full blown, real programming language that also incorporated Speech Acts. I happily started composing an reply to the email that started off with\nThat is so cool! ... Then I realized that the author of the email and language was none other than Frank McCabe, one of the designers of the Go! programming language (not to be confused with Google Go). My brain froze while it was thinking\n\u0026quot;OMG!!!! Frank McCabe, a real language designer, just emailed me!\u0026quot;. This unfortunately, made the rest of my email reply sound something like this\nFrank, That is so cool! herp derp derp Speech Acts herp derp John McCarthy derp... His programming language is the Star Programming Language. It was originally developed for use at a company that he worked at called Starview. It has since been open sourced and moved to git. I finally had a bit a spare time and I had been itching to give Star a look. To my pleasant surprise, despite my initial fumbling email impression, Frank was open a friendly to get me started in it. I have only scratched the surface in exploring the language, but I wanted to share my initial impressions, as well as point you to some beginner katas that I put together, so that you could join in the fun.\nCrash Overview Star is a strongly typed, functional language. It is not a pure functional language because is allows assignment and stateful objects, but the language is designed in a way that immutable functional programming is encouraged. The feel of the language is concise but human readable.\nStar is a coherent, general-purpose programming language that combines elements from a wide variety of existing languages as well as adding innovative elements of its own. Star inherits func- tional programming in general, a Haskell-style type system, an F#- style monad for parallel computations, and Concurrent ML for or- chestrating concurrent and parallel applications.\n\u0026ndash; Feel different on the Java platform: the star programming language http://dl.acm.org/citation.cfm?id=2500837\u0026amp;dl=ACM\u0026amp;coll=DL\u0026amp;CFID=354902651\u0026amp;CFTOKEN=90319052\nHello World The best way to get a feel for it is to look at a few examples. Of course, let\u0026rsquo;s start off with Hello World.\nmain() do { logMsg(info, \u0026#34;Hello World\u0026#34;); } Another way of doing our Hello World is in a worksheet. This feature is still in the works, but it will likely turn into a replacement for a REPL, being integrated into the editor. The import statement will also soon not be required. But a nice feature of using the worksheeet is that is a combined module and transcript of the session.\nimport worksheet worksheet{ show \u0026#34;hello world\u0026#34; } Here is what the output looks like:\nJun 11, 2014 11:21:09 AM INFO: \u0026quot;hello world\u0026quot; -\u0026gt; \u0026quot;hello world\u0026quot; at 4 info: execution took 0.053684428 Pattern Matching Let\u0026rsquo;s take a look at another example. This time a naive fib function with pattern matching.\nimport worksheet worksheet{ fib(0) is 0 fib(1) is 1 fib(n) is fib(n-1) + fib(n-2) assert fib(0)=0; assert fib(1)=1; assert fib(3)=2; assert fib(10)=55; } Notice how the fib function is defined with pattern matching. Also how the keyword \u0026ldquo;is\u0026rdquo; is used instead of an \u0026ldquo;=\u0026rdquo; to make the code flow more readable (IMO).\nThe output of running the program is:\nJun 11, 2014 3:32:38 PM INFO: fib(0) = 0 ok at 9 Jun 11, 2014 3:32:38 PM INFO: fib(1) = 1 ok at 10 Jun 11, 2014 3:32:38 PM INFO: fib(3) = 2 ok at 11 Jun 11, 2014 3:32:38 PM INFO: fib(10) = 55 ok at 12 info: execution took 0.039725132 Pattern Matching with Guards The declaration of pattern matching for functions can also include guards like in this fizzbuzz example\nfizzbuzz has type (integer) =\u0026gt; string fizzbuzz(N) where N%3=0 and N%5=0 is \u0026#34;fizzbuzz\u0026#34; fizzbuzz(N) where N%3=0 is \u0026#34;fizz\u0026#34; fizzbuzz(N) where N%5=0 is \u0026#34;buzz\u0026#34; fizzbuzz(N) default is \u0026#34;$N\u0026#34; Also note the type declaration. The type declaration is optional. The complier is smart enough to figure it out. Sometimes it is more readable to include the type declaration. But, it can be left out for more concise code.\nCons Lists One of the important collection types are cons lists. These are lists that you add to the front of and are destructed as the first element and then the rest of the list. To construct a cons list:\ntestNumbers is cons of {1;2;3;4;5;6;7;8;9;10;11;12;13;14;15} To use a cons list in a function with pattern matching:\nlistFizzBuzz has type (cons of integer) =\u0026gt; cons of string listFizzBuzz(nil) is nil listFizzBuzz(cons(x, xs)) is cons(fizzbuzz(x), listFizzBuzz(xs)) The function listFizzBuzz takes in a list of integers and turns it into a list of strings using the fizzbuzz function. If we evaluate:\ntestNumbers is cons of {1;2;3;4;5;6;7;8;9;10;11;12;13;14;15} result is listFizzBuzz(testNumbers) The result will look like\ncons of {\u0026#34;1\u0026#34;;\u0026#34;2\u0026#34;;\u0026#34;fizz\u0026#34;;\u0026#34;4\u0026#34;;\u0026#34;buzz\u0026#34;;\u0026#34;fizz\u0026#34;;\u0026#34;7\u0026#34;;\u0026#34;8\u0026#34;;\u0026#34;fizz\u0026#34;;\u0026#34;buzz\u0026#34;;\u0026#34;11\u0026#34;;\u0026#34;fizz\u0026#34;;\u0026#34;13\u0026#34;;\u0026#34;14\u0026#34;;\u0026#34;fizzbuzz\u0026#34;} There are other collection types such as arrays and relations, (which are really cool - you can do queries on them like a database), but I haven\u0026rsquo;t explored them well enough to really talk about yet.\nActors and Speech Acts Star has actors that use three Speech Acts: Notify, Request, and Query. The actors themselves can also be concurrent. I explored the Speech Act/ Actor model with an example from John McCarthy\u0026rsquo;s Elephant 2000 paper, which is a Airline Reservation system.\nTo use the notify speech act, you need to define what type the notifications are on the actors channel. In my case, the notifications are either going to be a book(string) method, or a cancel(string) method. To book a reservation for a person or cancel it.\ntype tx is book(string) or cancel(string); The actor is defined using:\nflight((FlightName has type string), (MaxPeople has type integer)) is actor{ var flightStatus := \u0026#34;open\u0026#34;; setFlightStatus(s) do { flightStatus := s }; on book(pname) on Tx do logMsg(info,\u0026#34;booking $pname on #FlightName\u0026#39;s flight: max #MaxPeople current $(size(plist))\u0026#34;); on book(pname) on Tx where size(plist) \u0026lt; MaxPeople do extend plist with pname; on book(pname) on Tx where size(plist) \u0026gt;= MaxPeople do logMsg(info, \u0026#34;sorry .. the flight is full\u0026#34;); on book(pname) on Tx where flightStatus != \u0026#34;open\u0026#34; do logMsg(info, \u0026#34;sorry .. the flight is no longer open\u0026#34;); on cancel(pname) on Tx do delete (X where X = pname) in plist; getPassengerList has type () =\u0026gt; list of string; getPassengerList() is plist; } There is some extra things in the code, but for right now, look at the book and cancel methods. These are the functions that will be called when the actor is notified like this:\nF is flight(\u0026#34;flight123\u0026#34;, 5) notify F with book(\u0026#34;Carin\u0026#34;) on Tx notify F with book(\u0026#34;Bob\u0026#34;) on Tx To query the actor we use :\nx is query F\u0026#39;s getPassengerList with getPassengerList() To use a request with the actor we use\nrequest F\u0026#39;s setFlightStatus to setFlightStatus(\u0026#34;closed\u0026#34;) Go Explore I have only scratched the surface of the language, but I have had a great time. I invite you to come take a look.\nWarning. Only the brave need apply. There is no StackOverflow. There is no user group or IRC channel yet. These are green fields to be discovered in the Open Source world. If it appeals to you as much as me, jump on in. Here are a few resources to get you going:\nStar-Lang Katas: Clone the repo or fork the repos. It has a shell script to compile and run the star programs. It also has a emacs mode plugin and a reference pdf. The most important part is that it has a template of katas ready for your to solve. Your challenge: uncomment the assertion and make the code pass. My solutions are in the solutions branch when you are done. If you finish all of them and want more, consider creating some and submitting a pull request :)\nI mentioned it earlier, but there is a great overview paper on the language itself here.\nFinally, here is the repo of the Star Language itself https://github.com/fmccabe/star. Checkout out the tests. There are tons of sample star programs that cover the language\u0026rsquo;s features.\n","permalink":"https://gigasquidsoftware.com/blog/2014/06/11/a-taste-of-the-star-programming-language/","summary":"\u003cp\u003eA while ago, I was \u003ca href=\"http://gigasquidsoftware.com/blog/2013/05/01/growing-a-language-with-haskell-and-instaparse/\"\u003eexploring creating a programming language with\nInstaparse\u003c/a\u003e.\nI ended up exploring some concepts of Speech Acts proposed by John\nMcCarthy by creating my first toy language called\n\u003ca href=\"http://gigasquidsoftware.com/blog/2013/06/04/babar-a-little-language-with-speech-acts-for-machines/\"\u003eBabar\u003c/a\u003e.\nShortly after posting a blog about it, I got an email from someone\nsaying that I might be interested in a full blown, real programming\nlanguage that also incorporated Speech Acts.  I happily started\ncomposing an reply to the email that started off with\u003c/p\u003e","title":"A Taste of the Star Programming Language"},{"content":"Once you have your hexapod assembled and running using the hand held controller, of course, your thoughts naturally turn to world domination.\nThe most powerful tool in the world is the Clojure REPL World domination requires the most powerful tools available. That of course calls for Clojure and the Clojure REPL. I recommend Emacs as the editor of choice of such an endeavor. However, it if you are content with city, state, or single country domination, other editors that support Clojure are also fine.\nConnect the XBee to your computer First, we need to get the computer to talk to the hexapod wirelessly. We can do this with a USB to Serial adapter that uses the paired XBee from the handheld commander.\nTake the XBee from the handheld commander\nand move it to the USB to serial adapter\nNow plug the usb into your computer.\nGet your Clojure ready In your clojure project, the only magic you need is the Serial Port library. Import the library and list your serial ports. Then open the one that shows up for you.\n(ns clj-hexapod.core (require [serial-port :as serial])) ;; Use this command to see what port your serial port ;; is assinged to (serial/list-ports) ;; replace the USB0 with whater it shows (def port (serial/open \u0026#34;/dev/ttyUSB0\u0026#34; 38400)) Since we are going to be talking to the hexapod. We need to send the commands in the same format that it is expecting. Basically, a packet of where the postions of the joystick are, as well as what buttons are pushed.\n(defn checksum [v] (mod (- 255 (reduce + v)) 256)) (defn vec-\u0026gt;bytes [v] (byte-array (map #(-\u0026gt; % (Integer.) (.byteValue) (byte)) v))) (defn build-packet [r-vert r-horz l-vert l-horz buttons] [255 ;header r-vert r-horz l-vert l-horz buttons 0 (checksum [r-vert r-horz l-vert l-horz buttons])]) (defn send [packet] (serial/write port (vec-\u0026gt;bytes packet))) From here, we can simply make functions for the joystick controls to go up and down\n;;values between 129-254 (defn up [speed] \u0026#34;joystick up for speed between 1-100\u0026#34; (if (good-range? speed) (int (+ 129 (* 125 (/ speed 100.0)))) CENTER)) ;;values between 0 and 125 (defn down [speed] \u0026#34;joystick down speed between 1-100\u0026#34; (if (good-range? speed) (int (- 125 (* 125 (/ speed 100.0)))) CENTER)) Then we can do things like walk, turn, and change the gait\n(defn walk-forward [speed] \u0026#34;walk forward speed between 1-100\u0026#34; (send (build-packet CENTER CENTER (up speed) CENTER 0))) (defn walk-backwards [speed] \u0026#34;walk backwards speed between 1-100\u0026#34; (send (build-packet CENTER CENTER (down speed) CENTER 0))) (defn walk-right [speed] \u0026#34;walk right speed between 1-100\u0026#34; (send (build-packet CENTER CENTER CENTER (up speed) 0))) (defn walk-left [speed] \u0026#34;walk right speed between 1-100\u0026#34; (send (build-packet CENTER CENTER CENTER (down speed) 0))) (defn turn-right [speed] \u0026#34;turn right speed between 1-100\u0026#34; (send (build-packet CENTER (up speed) CENTER CENTER 0))) (defn turn-left [speed] \u0026#34;turn left speed between 1-100\u0026#34; (send (build-packet CENTER (down speed) CENTER CENTER 0))) (defn change-gait [gait-key] (let [gait-num (gait-key gaits)] (send (build-packet CENTER CENTER CENTER CENTER gait-num)))) (defn stop [] \u0026#34;stop hexapod\u0026#34; (send (build-packet CENTER CENTER CENTER CENTER 0))) You can control it from the REPL with some simple commands\n(walk-forward 20) (walk-backwards 10) (walk-right 10) (walk-left 10) (turn-right 10) (turn-left 10) (change-gait :ripple-smooth) (change-gait :tripod-normal) (change-gait :ripple) (change-gait :amble) (stop) If you want to see the code, it is out on github as clj-hexapod. Please keep in mind that it is early days still, and I am still just exploring.\nPhoneix Code Firmware It is worth noting the the above code was meant to run with the default hexapod firmware. That is the \u0026ldquo;Nuke\u0026rdquo; firmware. There is another firmware, the Phoenix code, that gives the hexapod more lifelike moves and allows it to twist and shift is rather creepy ways.\nI just loaded it on the hexapod yesterday. The commander software changed too, so I will of course need to revisit the code, to add in the new moves. But here is a sneak preview of what it can do:\nThat is my daughter singing in the background\nThat\u0026rsquo;s all for now I hope I have given you pointers for getting started on your own world domination with Clojure and Hexapods. Remember to practice your laugh \u0026hellip;. Muhahaha :)\n","permalink":"https://gigasquidsoftware.com/blog/2014/03/20/world-domination-with-hexapods-and-clojure/","summary":"\u003cp\u003eOnce you have your \u003ca href=\"http://gigasquidsoftware.com/blog/2014/03/19/walking-with-hexapods/\"\u003ehexapod assembled and running using the hand held\ncontroller\u003c/a\u003e,\nof course, your thoughts naturally turn to world domination.\u003c/p\u003e\n\u003ch2 id=\"the-most-powerful-tool-in-the-world-is-the-clojure-repl\"\u003eThe most powerful tool in the world is the Clojure REPL\u003c/h2\u003e\n\u003cp\u003eWorld domination requires the most powerful tools available.  That of\ncourse calls for Clojure and the Clojure REPL.  I recommend Emacs\nas the editor of choice of such an endeavor.  However, it if you are\ncontent with city, state, or single country domination, other editors\nthat support Clojure are also fine.\u003c/p\u003e","title":"World Domination with Hexapods and Clojure"},{"content":"\nHere we see the PhantomX Hexapod thriving in the natural habitat of a cozy, climate controlled, modern house. But there was a time before the hexapod. In particular, there was a time of many hexapod parts and a high level software developer that somehow, despite her natural lack of mechanical skills, managed to bring it to life. This blog post endeavors to chronicle the high and low points of this journey. And perhaps, will make it easier for any other brave souls that would like to bring the Age of Hexapods into their homes.\nOh My! So Many Parts I wasn\u0026rsquo;t really mentally prepared for the vast amounts of parts in the kit. Here is a sampling:\n18 AX-12A Servos Top/ Bottom Body Plate 20 Brackets Arbotix Board 2 Xbees Lipo Battery \u0026amp; Charger Arbotix programmer 19 Cables **50,000 nuts and screws ** (Really only about 850 - but you get my point) First Things First The very first thing to do is to make sure that you have all the parts. Once I went through the checklist and double counted all my screws, I was relieved to go onto the next task of programming the Arbotix and assign ids to servos and center them. These steps consisted of:\nGetting the Arduino IDE going Loading the Drivers and Libraries Loading the ROS (Robot Operating System) on the Arbotix Board, so that it could be used to program the servos. Each of the servos have to be assigned a number. This will let the program know which part of the leg is which, so that it will eventually - hopefully, be able to walk. Once the id is given, a sticker is labeled on the servo for future use. Centering the servos is a VERY important step not to overlook. If you do not center the servos, you will get into the unfortunate circumstance of having to dissemble the robot, cry, recenter the servos, and then reassemble the robot. Please avoid.\nPutting It Together The assembly starts with the feet and legs first. I was so pleased when I got the feet assembled, that I considered knitting little baby hexapod booties.\nNext a servo and the tibia is added\nAnother servo and the tibia and femur is assembled\nFinally, another servo and the whole leg is assembled\nNewbie Advice I would like to pause for a minute to share some advice from my trial and errors in assembly thus far:\n**Don\u0026rsquo;t overtighten screws ** - More is not better. It makes things like plexiglass frames crack and break. Seating nuts in servos is hard - This isn\u0026rsquo;t really advice. Just moral support in your struggle. There are 18 servos and up to 20 nuts to seat in each servo. Assembling the body The body is where the board, battery and and cables go.\nAt long last, the legs can be attached to the body - with 120 screws of course.\nRound two of Newbie Advice For those who have never stripped wires and attached them to power supplies, like me, please mind that the wires are twisted so that the edges don\u0026rsquo;t fray out and short out everything requiring you to re-assign all the servos that lost their ids and much unscrewing, crying, and reassembling. When programming the Arbotix board. You must remove the Xbee, or it will not work. Also, did I mention not over-tightening screws? Also, the order in which you tighten the screws is important too. Try to tighten them all loosely in order, so you don\u0026rsquo;t stress the fiberglass parts and have something like this happen. It is Alive! Finally, the moment of truth. The hexapod is assembled and it is time to upload a test check on the board to make sure that everything is working alright.\nWalking with Hexapods The kit comes with a commander that you assemble of course. You can use it to control the hexapod with hand-held joysticks.\nThe moment of truth, when it finally took its very first steps, and the Age of Hexapods began.\nStay tuned for the next post of how to control the hexapod with your Clojure code and loading the Phoenix firmware that gives it a life-like moves\n","permalink":"https://gigasquidsoftware.com/blog/2014/03/19/walking-with-hexapods/","summary":"\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/images/posts/f70c0d04-13278398783_0bedfa7b40.jpg\"\u003e\u003c/p\u003e\n\u003cp\u003eHere we see the \u003ca href=\"http://www.trossenrobotics.com/phantomx-ax-hexapod.aspx\"\u003ePhantomX Hexapod\u003c/a\u003e thriving in the natural habitat of a\ncozy, climate controlled, modern house. But there was a time before\nthe hexapod.  In particular, there was a time of many hexapod parts\nand a high level software developer that somehow, despite her natural\nlack of mechanical skills, managed to bring it to life. This blog post\nendeavors to chronicle the high and low points of this journey. And\nperhaps, will make it easier for any other brave souls that would like\nto bring the \u003cem\u003eAge of Hexapods\u003c/em\u003e into their homes.\u003c/p\u003e","title":"Walking with Hexapods"},{"content":"\nYou don\u0026rsquo;t really understand how important someone is in your life until they are suddenly gone. I have had the honor and privilege of working, playing, and laughing alongside Jim Weirich for the last few years. He was an amazing man. I miss him dearly.\n##Think## Jim taught us how to think about computer programming. I once had a Physics professor tell me not to worry so much about the formulas and math. The most important thing was how to think. Everything thing after that would naturally fall into place. Jim embodied that philosophy for programming. The languages and algorithms poured almost effortlessly from his masterful fingers. He knew how to think about the problem, observe from a multitude of angles. Finally, bringing his experience, creativity, and humility to bear on it, he would shape it into a beautiful piece of code.\n##Make## Jim showed us how to make. He was a master craftsman and a maker. The care and joy that infused his work was inspiring. He loved the process of Test Driven Development. Green tests were always a celebration. The surprise of beautiful code emerging from a refactoring was treated as a gift. He is best known for his Rake build tool, but his testing library rspec-given is one that reminds me most of him and the way that he loved to craft code.\n##Care## Jim showed us how to care. Jim cared deeply about each and every person. While flying his drone in the office hallway, he would wave down a passing building maintenance worker and ask if they wanted to fly it. Over the course of the next few minutes, Jim would put them completely at ease and chat happily with them. He was like that to everyone. In the few days after his passing, many building workers, and people from other offices, that I only ever nodded at in passing, stopped by to give their sincere condolences his loss. He is without a doubt, the kindest person I have ever known. He took great joy in his faith and in his family. He would talk about his family all the time and how much they enjoyed each others company. He is without a doubt, one of the personally richest men I have ever known.\n##Share## Jim taught us how to share. Jim wanted to share his knowledge. He was a great teacher and presenter. He gave engaging presentations that took people on a journey with him, not only imparting knowledge, but becoming friends with him in the process. He was a pillar in the local Cincinnati technical community. He is the reason why myself and countless others were drawn to Ruby and the Ruby community.\n##Dream## Jim dreamed with us. He was a creative. He was also a singer, song writer, musician, and artist. He brought that creative spirit, curiosity, and love of learning to the technical world. I will cherish our lunches spent together flying our AR Drones, sometimes crashing them into walls and each other, while trying to find creative ways of controlling them with code. He was just lately exploring with the micro-quadcopters like the Proto-X. We had plans to make all our Spheros, Roombas, big drones, and little drones dance to live coded music. We were both auditing on Autonomous Mobile Robots to see what we could learn to help us with our robot dreams.\nI miss him dearly. I will cherish my memories of him and I am so grateful for all the ways he has enriched my life. I will remember that when I dream in code, he is still there with me.\nUntil that day when we will fly our friendly robots together again.\n","permalink":"https://gigasquidsoftware.com/blog/2014/02/22/remembering-jim/","summary":"\u003cp\u003e\u003cimg loading=\"lazy\" src=\"https://newcontext-production.s3.amazonaws.com/portrait/jim-weirich/medium_78048abb24eadb2017034c5ee10826f9.jpg\"\u003e\u003c/p\u003e\n\u003cp\u003eYou don\u0026rsquo;t really understand how important someone is in your life\nuntil they are suddenly gone. I have had the honor and privilege of\nworking, playing, and laughing alongside Jim Weirich for the last few\nyears.  He was an amazing man.  I miss him dearly.\u003c/p\u003e\n\u003cp\u003e##Think##\nJim taught us how to think about computer programming. I once had a\nPhysics professor tell me not to worry so\nmuch about the formulas and math. The most important thing was how to\n\u003cstrong\u003ethink\u003c/strong\u003e.\nEverything thing after that would\nnaturally fall into place.  Jim embodied that philosophy for\nprogramming.  The languages and algorithms poured almost\neffortlessly from his masterful fingers.  He knew how to \u003cstrong\u003ethink\u003c/strong\u003e about\nthe problem, observe from a multitude of angles.  Finally, bringing his\nexperience, creativity, and humility to bear on it, he would shape it into\na beautiful piece of code.\u003c/p\u003e","title":"Remembering Jim"},{"content":"The Hitchhiker\u0026rsquo;s Guide to Clojure posts now have a new home to make it easier to read them in a chronological fashion.\nhttp://hitchhikersclojure.com/\nThere is also a public repo - feel free to contribute spelling and grammar fixes, or your great ideas.\n","permalink":"https://gigasquidsoftware.com/blog/2014/02/16/hitchhikers-clojure-has-a-new-home/","summary":"\u003cp\u003eThe Hitchhiker\u0026rsquo;s Guide to Clojure posts now have a new home to make it\neasier to read them in a chronological fashion.\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://hitchhikersclojure.com/\"\u003ehttp://hitchhikersclojure.com/\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003eThere is also a public \u003ca href=\"https://github.com/gigasquid/hitchhikers-clojure\"\u003erepo\u003c/a\u003e - feel free to contribute spelling and\ngrammar fixes, or your great ideas.\u003c/p\u003e","title":"Hitchhiker's Clojure has a New Home"},{"content":"Amy and Frank fled down the stairs from her office and met an unexpected obstacle to their exit, a locked door. As they peered out the window, they saw yesterday\u0026rsquo;s Amy pull up in the parking space, get out, retrieve her laptop, and start to head in the front door.\n\u0026ldquo;Oh good, we can take your car\u0026rdquo;, said Frank.\nAmy took a second to recover from the shock of seeing what her hair really looked like from behind and then asked, \u0026ldquo;But, how can we get to it? The door is locked, and we can\u0026rsquo;t go back up to the office\u0026hellip; I would meet myself.\u0026rdquo;\nFrank smiled, pulled out the Hitchhiker\u0026rsquo;s Guide to Clojure and pulled up a page with the heading Locked Doors and Other Small Bothers.\nOne of the reasons for the surprising success of The Hitchhiker\u0026rsquo;s Guide to Clojure is helpful advice of on an assortment of practical matters.\nLocked doors are a common nuisance in modern times. Fortunately, Clojure provides a very handy function for such occasions, fnil. This commonly overlooked function, takes an existing function and returns a new function that allows you to specify a default for a nil parameter. For example, take this locked door:\n(defn locked-door [key] (if key \u0026#34;open\u0026#34; \u0026#34;nope - staying shut\u0026#34;)) (locked-door :key) ;=\u0026gt; \u0026#34;open\u0026#34; (locked-door nil) ;=\u0026gt; \u0026#34;nope - staying shut\u0026#34; In this case, the simple application of fnil will help remove this pesky obstacle.\n(def this-door (fnil locked-door :another-key-that-works)) (this-door :key) ;=\u0026gt; \u0026#34;open\u0026#34; (this-door nil) ;=\u0026gt; open Please be advised, that some doors are locked for a good reason. It is left to the user\u0026rsquo;s discretion. But it is highly recommended in Norway\u0026rsquo;s moose regions, to think twice.\nThey unlocked the door and headed for Amy\u0026rsquo;s car. She couldn\u0026rsquo;t decide whether she was surprised or not to find her keys in her pocket, so she gave up and just got in instead. After a short drive, they arrived at the zoo and navigated their way through various school groups and arrive at the Aquarium.\nAmy at this point, having prided herself on her adaptable nature, was still having trouble processing the latest events. She had discovered that Frank was a Datomic time traveller, the world was made of Clojure, and it was also about to be destroyed in a short future that she just came from. Her rational brain, (which was currently working way too hard), was quite relieved to be distracted by the sight of two really adorable otters. They were floating contentedly around the pool, occasionally stopping to crack an Abalone shell on their fuzzy tummies.\nHer rational brain, after having a nice breather, finally re-asserted itself and made Amy ask Frank:\n\u0026ldquo;Why are we here?\u0026rdquo;\n\u0026ldquo;Otters are the front-line Chrono-guards, of course.\u0026rdquo;\nHe went on to explain that otters are tasked with the important job of keeping a close watch on human civilization and making critical, minor adjustments to keep things on an even track. All those nature videos of otters cracking shells with rocks? They are really evaluating Clojure expressions crucial to our way of life. Most of the time, they prefer to do their work remote. They find floating on their backs in the peaceful waters the most productive work environment. However, sometimes they will construct zoos or aquariums, when their work requires them to keep a closer watch on some areas. In times of great need, they might even take a human form for a short while. Recently, one of their agents was inadvertently exposed and required a few extra Abalone shells to straighten out.\nFrank opened his pack and handed his evaluator to Amy to hold while fished out four mini-marshmallows. He gave two to Amy and then proceeded to put one in his ear and the other in his mouth. More remarkably still, he appeared to be speaking with the otters.\nMini-marshmallows are the best way to create portable Clojure core.async channels that won\u0026rsquo;t melt in your hands.\nTo construct a channel simply use chan\n(def talk-to-otters-chan (chan)) Channels by default are unbuffered, which keeps them at the mini-marshmallow size. It requires a rendezvous of a channel producer and consumer to communicate. In the case of otters, someone to talk to the otters and the otters, themselves, to listen. Be advised that with a regular blocking put \u0026gt;!!, the main thread will be blocked. That is, if you try to speak to the otter, you will be stuck there until it gets around to listening. This isn\u0026rsquo;t the best case for the talker if the otter was busy, so one approach would be to use a future to talk to the otter with a blocking put \u0026gt;!!.\n(future (\u0026gt;!! talk-to-otters-chan \u0026#34;Hello otters.\u0026#34;)) ;=\u0026gt;#\u0026lt;Future@3c371c41: :pending\u0026gt; (\u0026lt;!! talk-to-otters-chan) ;=\u0026gt; \u0026#34;Hello otters.\u0026#34; One could also use a buffered channel, but that increases the size of the marshmallow.\n(def talk-to-otters-chan (chan 10)) ;;create channel with buffer size 10 (\u0026gt;!! talk-to-otters-chan \u0026#34;Hello otters.\u0026#34;) ;=\u0026gt; nil (\u0026gt;!! talk-to-otters-chan \u0026#34;Do you know anything about the world ending?\u0026#34;) ;=\u0026gt; nil (\u0026lt;!! talk-to-otters-chan) ;=\u0026gt; \u0026#34;Hello otters.\u0026#34; (\u0026lt;!! talk-to-otters-chan) ;=\u0026gt; \u0026#34;Do you know anything about the world ending?\u0026#34; The best way to conserve space and time is to use asynchronous communication with go blocks that wont\u0026rsquo; block the threads. Inside these go blocks one can use regular non-blocking puts \u0026gt;! and gets \u0026lt;!.\n(def talk-to-otters-chan (chan)) (go (while true (println (\u0026lt;! talk-to-otters-chan)))) (\u0026gt;!! talk-to-otters-chan \u0026#34;Hello otters\u0026#34;) (\u0026gt;!! talk-to-otters-chan \u0026#34;Do you know anything about the world ending?\u0026#34;) (\u0026gt;!! talk-to-otters-chan \u0026#34;Also, you are really fuzzy and cute.\u0026#34;) ;; (This prints out in the REPL as you talk to the otters) Hello otters Do you know anything about the world ending? Also, you are really fuzzy and cute. This compact, lightweight, and asynchronous method of communication is well suited to conversations and messaging of all sorts, including conversing with human, animals, and other Clojure-based life forms.\n(def talk-chan (chan)) (def listen-chan (chan)) (go (while true (println (\u0026lt;! listen-chan)))) (go (while true (\u0026gt;! listen-chan (str \u0026#34;You said: \u0026#34;(\u0026lt;! talk-chan) \u0026#34; \u0026#34; \u0026#34;Do you have any Abalone?\u0026#34; )))) (\u0026gt;!! talk-chan \u0026#34;Hello otters\u0026#34;) (\u0026gt;!! talk-chan \u0026#34;Do you know anything about the world ending?\u0026#34;) (\u0026gt;!! talk-chan \u0026#34;Also, you are really fuzzy and cute.\u0026#34;) ;; (This prints out in the REPL as you talk to the otters) You said: Hello otters Do you have any Abalone? You said: Do you know anything about the world ending? Do you have any Abalone? You said: Also, you are really fuzzy and cute. Do you have any Abalone? Amy put one of the mini-marshmallows in her ear. She immediately began to hear the conversation that Frank was having with the otters.\n\u0026ldquo;But who would want to destroy the entire world? That is really kinda over-board.\u0026rdquo;\n\u0026ldquo;I don\u0026rsquo;t really know, but there was someone on Galactic Hacker News the other day that was quite tiffed over the idea that Clojure was considered a Lisp.\u0026rdquo;\nAmy reached to put the other marshmallow in her mouth to ask a very important question. But unfortunately, as she moved her hand, she accidentally pushed the big red Source button on the evaluator. Suddenly, she and Frank were swept up in a vortex that spun them around and sucked them down into the ground.\n","permalink":"https://gigasquidsoftware.com/blog/2014/02/15/hitchhikers-guide-to-clojure-part-3/","summary":"\u003cp\u003eAmy and Frank fled down the stairs from her office and met an\nunexpected obstacle to their exit, a locked door.  As\nthey peered out the window, they saw yesterday\u0026rsquo;s Amy pull up in the\nparking space, get out, retrieve her laptop, and start to head in\nthe front door.\u003c/p\u003e\n\u003cp\u003e\u0026ldquo;Oh good, we can take your car\u0026rdquo;, said Frank.\u003c/p\u003e\n\u003cp\u003eAmy took a second to recover from the shock of seeing what her hair really\nlooked like from behind and then asked, \u0026ldquo;But, how can we get to it?\nThe door is locked, and we\ncan\u0026rsquo;t go back up to the office\u0026hellip; I would meet myself.\u0026rdquo;\u003c/p\u003e","title":"Hitchhiker's Guide to Clojure - Part 3"},{"content":"Amy and Frank were hurtled quite rapidly through time and space after attaching themselves to a transaction headed through the Datomic Transactor. From there things slowed down a bit, then took a sharp left and ricocheted off again with incredible speed until they landed in another Datomic Peer, and finally appeared in the same room. Amy was quite startled by the anti-climatic nature of the whole dematerializing and rematerializing in the same exact spot, and didn\u0026rsquo;t really know what to do next. She surveyed her office and found it exactly the same, except for two distinct details. For one, the pistachio shells had disappeared, and for another, the date on the computer showed yesterday at 8:00 am. She tried to connect these facts rationally with the pistachios in her pocket and finally said,\n\u0026ldquo;I am about to come into work.\u0026rdquo;\nFrank, who was busily hunting through his blue zippered pack around his waist, looked up briefly.\n\u0026ldquo;Well, we better get out of here then, I only have a blue fanny pack.\u0026rdquo;\nThe Hitchhiker\u0026rsquo;s Guide to Clojure explains that the \u0026ldquo;fanny pack\u0026rdquo;, or \u0026ldquo;bum bag\u0026rdquo;, is the symbol of a licensed Chrono-agent. The rank of the Chrono-agent can be clearly determined by its color on the ROYGBIV scale.\nThe origins of this licensing method can be traced to an embarrassing incident in human history known as \u0026ldquo;The Great Flood\u0026rdquo;. A junior Chrono-agent was trying to increase the yield of a tomato crop during a dry spell and was trying to do the following recursive function in his evaluator:\n(defn rain [days] (when (pos? days) (println (str \u0026#34;Rain: \u0026#34; days)) (rain (dec days)))) (rain 5) ;;Output ;; Rain: 5 ;; Rain: 4 ;; Rain: 3 ;; Rain: 2 ;; Rain: 1 Unfortunately, he made the rookie mistake of forgetting to decrement the days before passing it to the recursive function.\n(dec 5) ;=\u0026gt; 4 The result of which was severely overwatered tomatoes.\n(defn rain [days] (when (pos? days) (println (str \u0026#34;Rain: \u0026#34; days)) (rain days))) (rain 5) ;; Rain: 5 ;; Rain: 5 ;; Rain: 5 ;; Rain: 5 ;; Rain: 5 ;; ...(you get the idea) It is interesting to note that he could he written the same function with a recur instead.\n(defn rain [days] (when (pos? days) (println (str \u0026#34;Rain: \u0026#34; days)) (recur days))) (rain 5) ;;Output ;; Rain: 5 ;; Rain: 5 ;; Rain: 5 ;; Rain: 5 ;; Rain: 5 That would have had the nice effect of not consuming the stack, (which is fabulous for constructing those lovely fibonacci sea shells for beach vacations), but without decrementing the parameter in the recursive call, it wouldn\u0026rsquo;t have really helped.\nA senior Chrono-agent was dispatched to sort out the mess. By the time he got there and stopped the rain, there was not much left to work with. Thankfully, he was quite versed in lazy and infinite aspects of Clojure. For instance, take this vector of 2 chickens:\n[:hen :rooster] It can be transformed into an infinite lazy list of chickens by using cycle.\n(cycle [:hen :rooster]) What really set the senior Chrono-agent apart from his junior colleague, was that he did not put the infinite sequence in the evaluator. If he had, there would have been another embarrassing incident in human history, this time involving an over-abundance of poultry. Instead, he used take to get the first n infinite chickens.\n(take 5 (cycle [:hen :rooster])) ;;=\u0026gt; (:hen :rooster :hen :rooster :hen) (take 10 (cycle [:hen :rooster])) ;;=\u0026gt; (:hen :rooster :hen :rooster :hen :rooster :hen :rooster :hen :rooster) After that, the council of Chrono-agents, decided to license evaluator use. Low-level recursion requires the 2nd highest indigo level rank. The highest violet rank, of course, belonging only to the Macro Masters. All lower levels are required to stick to the safer, higher level abstractions like for, map, or reduce.\nAmy was still watching Frank busily rumaging through his pack in the office . Finally he found what he was looking for, his hand emerging triumphantly with a fistful of mini-marshmallows.\n\u0026ldquo;Got it. Come on, let\u0026rsquo;s go! Someone is trying to destroy the world and we need to see the otters.\u0026rdquo;\n","permalink":"https://gigasquidsoftware.com/blog/2014/02/08/hitchhikers-guide-to-clojure-part-2/","summary":"\u003cp\u003eAmy and Frank were hurtled quite rapidly through time and space after\nattaching themselves to a transaction headed through the\n\u003ca href=\"http://docs.datomic.com/transactions.html\"\u003eDatomic Transactor\u003c/a\u003e. From\nthere things slowed down a bit, then took a sharp left and\nricocheted off again with incredible speed until they landed in another\n\u003ca href=\"http://docs.datomic.com/architecture.html\"\u003eDatomic Peer\u003c/a\u003e, and finally\nappeared in the same room.  Amy was quite startled by the\nanti-climatic nature of the whole dematerializing and rematerializing\nin the same exact spot, and didn\u0026rsquo;t really know what to do next.  She\nsurveyed her office and found it exactly the same,\nexcept for two distinct details.  For one, the pistachio shells had\ndisappeared, and for another, the date on the computer showed\nyesterday at 8:00 am.  She tried to connect these facts rationally\nwith the pistachios in her pocket and finally said,\u003c/p\u003e","title":"Hitchhiker's Guide to Clojure - Part 2"},{"content":"\nThe following is a cautionary example of the unpredictable combination of Clojure, a marathon viewing of the BBC\u0026rsquo;s series \u0026ldquo;The Hitchhiker\u0026rsquo;s Guide to the Galaxy\u0026rdquo;, and a questionable amount of cheese.\nThere have been many tourism guides to the Clojure programming language. Some that easily come to mind for their intellectual erudition and prose are \u0026ldquo;The Joy of Touring Clojure\u0026rdquo;, \u0026ldquo;Touring Clojure\u0026rdquo;, \u0026ldquo;Clojure Touring\u0026rdquo;, and the newest edition of \u0026ldquo;Touring Clojure Touring\u0026rdquo;. However, none has surpassed the wild popularity of \u0026ldquo;The Hitchhiker\u0026rsquo;s Guide to Clojure\u0026rdquo;. It has sold over 500 million copies and has been on the \u0026ldquo;BigInt\u0026rsquo;s Board of Programming Language Tourism\u0026rdquo; for the past 15 years. While, arguably, it lacked the in-depth coverage of the other guides, it made up for it in useful practical tips, such as what to do if you find a nil in your pistachio. Most of all, the cover had the following words printed in very large letters: Don\u0026rsquo;t Worry About the Parens.\nTo tell the story of the book, it is best to tell the story of two people whose lives were affected by it: Amy Denn, one of the last remaining [Pascal](http://en.wikipedia.org/wiki/Pascal_(programming_language) developers in Cincinnati, and Frank Pecan, a time traveler, guidebook reseacher, and friend of Amy.\nAmy, at this moment, was completely unaware of the chronological advantages of her friend, being preoccupied with the stark fact that she was about to be fired. She had been given a direct order from her CEO to deploy the code at 3:05pm. It was now 3:00pm and she had realized that if she did so, all the data painstaking collected about the effects of Throat Singing on the growth rate of tomatoes would be erased. Unfortunately, the CEO did not really understand or trust anything having to do with technology or programming. In truth, the only two things that he seemed to care about were tomatoes and checklists of unreasonable things. The fact that no course of action available to her in the next 5 minutes would help her employment situation, agitated Amy so much that she was violently shelling and eating pistachio nuts.\nThe \u0026ldquo;Hitchhiker\u0026rsquo;s Guide to Clojure\u0026rdquo; says that pistachios are Nature\u0026rsquo;s most perfect s-expression. An s-expression is recursively composed of s-expressions or an atom. In the case of the humble pistachio, the atom is the nut inside. The atom simply evaluates to itself. This is best seen is an example where the following expressions are evaluated in the Clojure REPL\n\u0026#34;hi\u0026#34; ;;=\u0026gt; \u0026#34;hi\u0026#34; 1 ;;=\u0026gt; 1 true ;;=\u0026gt; true nil ;;=\u0026gt; nil Which leads to the very practical tip of what to do if you find a nil in your pistachio. The answer, of course, is to be thankful that you have a value that represents the absence of a value - and to get another pistachio.\nIn Clojure, a s-expression is written with parens. The first element within the parens is an operator or function and the rest of the elements are treated as data, some of which can be s-expression themselves.\n(+ 1 2) ;;=\u0026gt; 3 (+ 1 (+ 2 2)) ;;=\u0026gt; 5 Considering the pistachio again, we can think of the nut in the shell as an s-expression, (providing we also imagine an operator or function right in front of the nut).\nHere we define a function that will turn the nut red, by appending the string \u0026ldquo;red\u0026rdquo; to the nut-name.\n(defn red [nut] (str \u0026#34;red \u0026#34; nut)) (red \u0026#34;nut1\u0026#34;) ;;=\u0026gt; \u0026#34;red nut1\u0026#34; Notice that if we put a quote in front of the expression, it will no longer be evaluated.\n\u0026#39;(red \u0026#34;nut1\u0026#34;) ;;=\u0026gt; (red \u0026#34;nut1\u0026#34;) quoting the expression turns it into a list, which we can then manipulate with other s-expressions (code as data).\n(first \u0026#39;(red \u0026#34;nut1\u0026#34;)) ;;=\u0026gt; red (last \u0026#39;(red \u0026#34;nut1\u0026#34;)) ;;=\u0026gt; \u0026#34;nut1\u0026#34; If we try to evaluate the s-expression with just the nut name in the parens, we get an error because there is no function in the first slot.\n(\u0026#34;nut1\u0026#34;) ;;=\u0026gt; ClassCastException java.lang.String cannot be cast to clojure.lang.IFn The whole thing of having to have a function in front of the nut in the pistachio has invited much heated debate on the suitability of pistachios being held up as the paragon of an s-expression. But critics have failed to explain the corroborating evidence of red pistachio nuts, or find a more suitable nut.\nAmy\u0026rsquo;s time traveling friend, Frank, is due to appear on the scene momentarily to reveal that the whole world is really made of Clojure Datomic datoms. Furthermore, a transaction is going to be evaluated soon, which will retract all the facts on EVERYTHING. The practical effect of this will be that nothing will have an attributes. A world without any attributes at all would be quite boring and, for all purposes, be non-existent. Luckily for Amy, Frank is a Datomic Time Traveller and has a hand-held \u0026ldquo;evaluator\u0026rdquo; which will save them. Also luckily, the readers will be spared dialog, since the author can never figure out where to put the punctuation and is really rubbish at it. Only one phrase will be illustrated. This is the rather important one, having been uttered by Amy after it was explained to her that she, and the entire world around her, was entirely composed of Clojure:\n\u0026ldquo;Isn\u0026rsquo;t that the language with a lot of parens?\u0026rdquo;\nTo which, Frank handed her the \u0026ldquo;Hitchhiker\u0026rsquo;s Guide to Clojure\u0026rdquo; and pointed to the words on the front cover, \u0026ldquo;Don\u0026rsquo;t Worry About the Parens.\u0026rdquo;, and turned to the first page.\n\u0026ldquo;There is absolutely no need to worry about the parens. It is known today that the first really important discovery of humankind was not fire, but Paredit. Paredit mode magically acts to insert and balance the right parens to the point where they actually can no longer be seen. This is evident by just looking around you. The world is made of Clojure and there are millions, billions, and trillions of parens all around you and your tea cup right now. Yet, you don\u0026rsquo;t see them. Paredit mode.\u0026rdquo;\nAt the urging of Frank, Amy quickly stuffed the remaining pistachios in her pockets while he readied his evaluator. The display showed some large integer value, that decreased as he pushed the buttons on the console. Finally, he pushed the large red button and two parens started glowing on either side of them \u0026hellip; and they disappeared.\n","permalink":"https://gigasquidsoftware.com/blog/2014/02/01/hitchhikers-guide-to-clojure/","summary":"\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/images/posts/c6aad747-12258585125_36e8fdee1e.jpg\"\u003e\u003c/p\u003e\n\u003cp\u003e\u003cem\u003eThe following is a cautionary example of the unpredictable\ncombination of Clojure, a marathon viewing of the BBC\u0026rsquo;s series \u0026ldquo;The\nHitchhiker\u0026rsquo;s Guide to the Galaxy\u0026rdquo;, and a questionable amount of\ncheese.\u003c/em\u003e\u003c/p\u003e\n\u003cp\u003eThere have been many tourism guides to the\n\u003ca href=\"http://clojure.org/\"\u003eClojure\u003c/a\u003e programming language.  Some that easily\ncome to mind for their intellectual erudition and prose are \u0026ldquo;The Joy\nof Touring Clojure\u0026rdquo;, \u0026ldquo;Touring Clojure\u0026rdquo;, \u0026ldquo;Clojure Touring\u0026rdquo;, and the\nnewest edition of \u0026ldquo;Touring Clojure Touring\u0026rdquo;.  However, none has\nsurpassed the wild popularity of \u0026ldquo;The Hitchhiker\u0026rsquo;s Guide to Clojure\u0026rdquo;.\nIt has sold over 500 million copies and has been on the \u0026ldquo;BigInt\u0026rsquo;s\nBoard of Programming Language Tourism\u0026rdquo; for the past 15 years. While,\narguably, it\nlacked the in-depth coverage of the other guides, it made up for it in\nuseful practical tips, such as what to do if you find a nil in your\npistachio.  Most of all, the cover had the following words printed in\nvery large letters: \u003cstrong\u003eDon\u0026rsquo;t Worry About the Parens\u003c/strong\u003e.\u003c/p\u003e","title":"Hitchhiker's Guide to Clojure"},{"content":"\nAfter attending a local Lean Startup Circle meetup, I decided to write about some of my experiences with the Lean Startup Methodology from a software developer\u0026rsquo;s point of view.\nWhy should you care about the Lean Startup Methodology? As software developer, I put my passion, honed expertise, and time into crafting a digital product or service. One of the worst things that can happen is that when it is released, no one uses it or wants it. You can build a absolutely beautiful software product that scales to the nines. But if you build the wrong thing, it is a failure.\nThe Lean Startup Methodology is basically a scientific approach to developing business and products. You analyze your assumptions and then devise experiments to test your hypotheses. One of the ways that you can test them, is by talking to people and doing customer interviews.\nTalking to Random People is Terrifying The prospect of talking to random people on the street is a terrifying prospect for me as a semi-introverted software developer. It is also incredibly useful to get out of the office and actually get feedback. These tips come from a Lean Startup Weekend in Columbus at the Neo office, where I successfully got out of my comfort zone and engaged in customer interviews.\nBackground: Our team was designing experiments around creating an app for Food Trucks. The fundamental assumption that we wanted to validate was - \u0026ldquo;People will pay money for a phone app that will tell them where all the Food Trucks are.\u0026rdquo; So we headed downtown to the local food market. This was a place where there were local artisan food vendors in a food hall. It seemed like an ideal place to find people interested in good food and Food Trucks.\nTip #1 - You will suck at first, but it gets better The first few people I tried to talk were complete failures. I felt like a complete idiot. Do not get discouraged. It helps if you go with someone else for moral support, although you should interview people by yourself, so they don\u0026rsquo;t feel intimidated.\nTip #2 - Have your questions written down Come prepared with the questions that you want to ask people, so you don\u0026rsquo;t have a brain freeze with nervousness. However, I found I got people to talk to me more if I didn\u0026rsquo;t carry the pad of paper with me. Basically anything you can do to look less like a marketer helps.\nTip #3 - Tell them what you are trying to build first DO NOT START OUT LIKE THIS: \u0026ldquo;Can I ask you a few questions?\u0026rdquo; This never worked. Again, this is what a marketer would say. I got my best responses by telling people that I was a software developer looking to build a app for Food Trucks. In most cases, they were happy to give advice on whether they would use the app and how much they would pay for it.\nTip #4 - Write down your results right away Memory is a fleeting thing. Try to record the results of your conversation right away. Take the notepad from your pocket and go to a corner or table and note everything down, before you forgot it all. Also try to write down what the person said, not just your interpretation. If someone is helping you interview, you can have one person be a scribe, while one person talks.\nTip #5 - Give Gifts If you have any funding available for this endeavor, you can get a stack of Amazon $10 gift cards for people\u0026rsquo;s time. This was some advice given to us. I didn\u0026rsquo;t actually try it for this particular outing, but I have heard that others have used it very successfully.\nGetting out of your Comfort Zone is Scary but Rewarding I certainly got out of my comfort zone as a developer that weekend. But the end result was worth it. We ended up disproving our hypothesis the people would pay for our app. Almost all the people we interviewed said that they would download the app, but no one was willing to pay for it. We invalidated a core assumption, it was a success.\nWe could move on to testing and validating another idea that could be a viable business product.\nBuild things that matter. Build well. Build the right things.\nThanks to Scott Burwinkel for helping review this post for me - you rock ","permalink":"https://gigasquidsoftware.com/blog/2014/01/09/lean-customer-interview-tips-for-the-introverted-developer/","summary":"\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/images/posts/cbc0d253-4356643150_9b26a637e9.jpg\"\u003e\u003c/p\u003e\n\u003cp\u003eAfter attending a local Lean Startup Circle meetup, I decided to write\nabout some of my experiences with the\n\u003ca href=\"http://theleanstartup.com/\"\u003eLean Startup Methodology\u003c/a\u003e from a software\ndeveloper\u0026rsquo;s point of view.\u003c/p\u003e\n\u003ch2 id=\"why-should-you-care-about-the-lean-startup-methodology\"\u003eWhy should you care about the Lean Startup Methodology?\u003c/h2\u003e\n\u003cp\u003eAs software developer, I put my passion, honed expertise, and time\ninto crafting a digital product or service. One of the worst things\nthat can happen is that when it is released, no one uses it or wants\nit. You can build a absolutely beautiful software product that scales\nto the nines. But if you build the wrong thing, it is a failure.\u003c/p\u003e","title":"Lean Customer Interview Tips for the Introverted Developer"},{"content":"After having spent some time recently looking at top-down AI, I thought I would spend some time looking at bottom\u0026rsquo;s up AI, machine learning and neural networks.\nI was pleasantly introduced to @mikea\u0026rsquo;s core.matrix at Clojure Conj this year and wanted to try making my own neural network using the library. The purpose of this blog is to share my learnings along the way.\nWhat is a neural network? A neural network is an approach to machine learning that involves simulating, (in an idealized way), the way our brains work on a biological level. There are three layers to neural network: the input layer, the hidden layers, and the output layer. Each layer consists of neurons that have a value. In each layer, each neuron is connected to the neuron in the next layer by a connection strength. To get data into the neural network, you assign values to the input layer, (values between 0 and 1). These values are then \u0026ldquo;fed forward\u0026rdquo; to the hidden layer neurons though an algorithm that relies on the input values and the connection strengths. The values are finally \u0026ldquo;fed forward\u0026rdquo; in a similar fashion to the output layer. The \u0026ldquo;learning\u0026rdquo; portion of the neural network comes from \u0026ldquo;training\u0026rdquo; the network data. The training data consists of a collection of associated input values and target values. The training process at a high level looks like this:\nFeed forward input values to get the output values How far off are the output values from the target values? Calculate the error values and adjust the strengths of the network Repeat until you think it has \u0026ldquo;learned\u0026rdquo; enough, that is when you feed the input values in the result of the output values are close enough to the target you are looking for The beauty of this system is that the neural network, (given the right configuration and the right training), can approximate any function - just by exposing it to data.\nStart Small I wanted to start with a very small network so that I could understand the algorithms and actually do the maths for the tests along the way. The network configuration I chose is one with 1 hidden layer. The input layer has 2 neurons, the hidden layer has 3 neurons and the output layer has 2 neurons.\n;;Neurons ;; Input Hidden Output ;; A 1 C ;; B 2 D ;; 3 ;; Connection Strengths ;; Input to Hidden =\u0026gt; [[A1 A2 A3] [B1 B2 B3]] ;; Hidden to Output =\u0026gt; [[1C 1D] [2C 2D] [3C 3D]] In this example we have:\nInput Neurons: neuronA neuronB Hidden Neurons: neuron1 neuron2 neuron3 Output Neurons: neuronC neuronD Connections between the Input and Hidden Layers neuronA-neuron1 neuronA-neuron2 neuronA-neuron3 neuronB-neuron1 neuronB-neuron2 neuronB-neuron3 Connections betwen the Hidden and Output Layers neuron1-nerounC neuron1-nerounD neuron2-nerounC neuron2-nerounD neuron3-nerounC neuron3-nerounD To give us a concrete example to work with, let\u0026rsquo;s actually assign all our neurons and connection strengths to some real values.\n(def input-neurons [1 0]) (def input-hidden-strengths [ [0.12 0.2 0.13] [0.01 0.02 0.03]]) (def hidden-neurons [0 0 0]) (def hidden-output-strengths [[0.15 0.16] [0.02 0.03] [0.01 0.02]]) Feed Forward Alright, we have values in the input neuron layer, let\u0026rsquo;s feed them forward through the network. The new value of neuron in the hidden layer is the sum of all the inputs of its connections multiplied by the connection strength. The neuron can also have its own threshold, (meaning you would subtract the threshold from the sum of inputs), but to keep things a simple as possible in this example, the threshold is 0 - so we will ignore it. The sum is then feed into an activation function, that has an output in the range of -1 to 1. The activation function is the tanh function. We will also need the derivative of the tanh function a little later when we are calculating errors, so we will define both here.\n(def activation-fn (fn [x] (Math/tanh x))) (def dactivation-fn (fn [y] (- 1.0 (* y y)))) (defn layer-activation [inputs strengths] \u0026#34;forward propagate the input of a layer\u0026#34; (mapv activation-fn (mapv #(reduce + %) (* inputs (transpose strengths))))) Note how nice core.matrix works on multipling vectors \u0026lt;3.\nSo now if we calculate the hidden neuron values from the input [1 0], we get:\n(layer-activation input-neurons input-hidden-strengths) ;=\u0026gt; [0.11942729853438588 0.197375320224904 0.12927258360605834] Let\u0026rsquo;s just remember those hidden neuron values for our next step\n(def new-hidden-neurons (layer-activation input-neurons input-hidden-strengths)) Now we do the same thing to calculate the output values\n(layer-activation new-hidden-neurons hidden-output-strengths) ;=\u0026gt; [0.02315019005321053 0.027608061500083565] (def new-output-neurons (layer-activation new-hidden-neurons hidden-output-strengths)) Alright! We have our answer [0.02315019005321053 0.027608061500083565]. Notice that the values are pretty much the same. This is because we haven\u0026rsquo;t trained our network to do anything yet.\nBackwards Propagation To train our network, we have to let it know what the answer,(or target), should be, so we can calculate the errors and finally update our connection strengths. For this simple example, let\u0026rsquo;s just inverse the data - so given an input of [1 0] should give us an output of [0 1].\n(def targets [0 1]) Calculate the errors of the output layer The first errors that we need to calculate are the ones for the output layer. This is found by subtracting the target value form the actual value and then multiplying by the gradient/ derivative of the activation function\n(defn output-deltas [targets outputs] \u0026#34;measures the delta errors for the output layer (Desired value – actual value) and multiplying it by the gradient of the activation function\u0026#34; (* (mapv dactivation-fn outputs) (- targets outputs))) (output-deltas targets new-output-neurons) ;=\u0026gt; [-0.023137783141771645 0.9716507764442904] Great let\u0026rsquo;s remember this output deltas for later\n(def odeltas (output-deltas targets new-output-neurons)) Calculate the errors of the hidden layer The errors of the hidden layer are based off the deltas that we just found from the output layer. In fact, for each hidden neuron, the error delta is the gradient of the activation function multiplied by the weighted sum of the ouput deltas of connected ouput neurons and it\u0026rsquo;s connection strength. This should remind you of the forward propagation of the inputs - but this time we are doing it backwards with the error deltas.\n(defn hlayer-deltas [odeltas neurons strengths] (* (mapv dactivation-fn neurons) (mapv #(reduce + %) (* odeltas strengths)))) (hlayer-deltas odeltas new-hidden-neurons hidden-output-strengths) ;=\u0026gt; [0.14982559238071416 0.027569216735265096 0.018880751432503236] Great let\u0026rsquo;s remember the hidden layer error deltas for later\n(def hdeltas (hlayer-deltas odeltas new-hidden-neurons hidden-output-strengths)) Updating the connection strengths Great! We have all the error deltas, now we are ready to go ahead and update the connection strengths. In general this is the same process for both the hidden-output connections and the input-hidden connections.\nweight-change = error-delta * neuron-value new-weight = weight + learning rate * weight-change The learning rate controls how fast the weigths and errors should be adjusted. It the learning rate is too high, then there is the danger that it will converge to fit the solution too fast and not find the best solution. If the learning rate is too low, it may never actually converge to the right solution given the training data that it is using. For this example, let\u0026rsquo;s use a training rate of 0.2\n(defn update-strengths [deltas neurons strengths lrate] (+ strengths (* lrate (mapv #(* deltas %) neurons)))) Update the hidden-output strengths Updating this layer we are going to look at\nweight-change = odelta * hidden value new-weight = weight + (learning rate * weight-change) (update-strengths odeltas new-hidden-neurons hidden-output-strengths learning-rate) ;=\u0026gt; [[0.14944734341306073 0.18320832546991603] [0.019086634528619688 0.06835597662949369] [0.009401783798869296 0.04512156124675721]] Of course, let\u0026rsquo;s remember these values too\n(def new-hidden-output-strengths (update-strengths odeltas new-hidden-neurons hidden-output-strengths learning-rate)) Update the input-hidden strengths We are going to do the same thing with the input-hidden strengths too.\nweight-change = hdelta * input value new-weight = weight + (learning rate * weight-change) (update-strengths hdeltas input-neurons input-hidden-strengths learning-rate) ;=\u0026gt; [[0.14996511847614283 0.20551384334705303 0.13377615028650064] [0.01 0.02 0.03]] These are our new strengths\n(def new-input-hidden-strengths (update-strengths hdeltas input-neurons input-hidden-strengths learning-rate)) Putting the pieces together We have done it! In our simple example we have:\nForward propagated the input to get the output Calculated the errors from the target through backpropogation Updated the connection strengths/ weights We just need to put all the pieces together. We\u0026rsquo;ll do this with the values that we got earlier to make sure it is all working.\nConstruct a network representation It would be nice if we could represent an entire neural network in a data structure. That way the whole transformation of feeding forward and training the network could give us a new network back. So lets define the data structure as [input-neurons input-hidden-strengths hidden-neurons hidden-output-strengths output-neurons].\nWe will start off with all the values of the neurons being zero.\n(def nn [ [0 0] input-hidden-strengths hidden-neurons hidden-output-strengths [0 0]]) Generalized feed forward Now we can make a feed forward function that takes this network and constructs a new network based on input values and the layer-activation function that we defined earlier.\n(defn feed-forward [input network] (let [[in i-h-strengths h h-o-strengths out] network new-h (layer-activation input i-h-strengths) new-o (layer-activation new-h h-o-strengths)] [input i-h-strengths new-h h-o-strengths new-o])) This should match up with the values that we got earlier when we were just working on the individual pieces.\n(testing \u0026#34;feed forward\u0026#34; (is (== [input-neurons input-hidden-strengths new-hidden-neurons hidden-output-strengths new-output-neurons] (feed-forward [1 0] nn)))) Generalized update weights / connection strengths We can make a similiar update-weights function that calculate the errors and returns back a new network with the updated weights\n(defn update-weights [network target learning-rate] (let [[ in i-h-strengths h h-o-strengths out] network o-deltas (output-deltas target out) h-deltas (hlayer-deltas o-deltas h h-o-strengths) n-h-o-strengths (update-strengths o-deltas h h-o-strengths learning-rate) n-i-h-strengths (update-strengths h-deltas in i-h-strengths learning-rate)] [in n-i-h-strengths h n-h-o-strengths out])) This too should match up with the pieces from the earlier examples.\n(testing \u0026#34;update-weights\u0026#34; (is ( == [input-neurons new-input-hidden-strengths new-hidden-neurons new-hidden-output-strengths new-output-neurons] (update-weights (feed-forward [1 0] nn) [0 1] 0.2)))) Generalized train network Now we can make a function that takes input and a target and feeds the input forward and then updates the weights.\n(defn train-network [network input target learning-rate] (update-weights (feed-forward input network) target learning-rate)) (testing \u0026#34;train-network\u0026#34; (is (== [input-neurons new-input-hidden-strengths new-hidden-neurons new-hidden-output-strengths new-output-neurons] (train-network nn [1 0] [0 1] 0.2)))) Try it out! We are ready to try it out! Let\u0026rsquo;s train our network on a few examples of inversing the data\n(def n1 (-\u0026gt; nn (train-network [1 0] [0 1] 0.5) (train-network [0.5 0] [0 0.5] 0.5) (train-network [0.25 0] [0 0.25] 0.5))) We\u0026rsquo;ll also make a helper function that just returns the output neurons for the feed-forward function.\n(defn ff [input network] (last (feed-forward input network))) Let\u0026rsquo;s look at the results of the untrained and the trained networks\n;;untrained (ff [1 0] nn) ;=\u0026gt; [0.02315019005321053 0.027608061500083565] ;;trained (ff [1 0] n1) ;=\u0026gt; [0.03765676393050254 0.10552175312900794] Whoa! The trained example isn\u0026rsquo;t perfect, but we can see that it is getting closer to the right answer. It is learning!\nMOR Training Data Well this is really cool and it is working. But it would be nicer to be able to present a set of training data for it to learn on. For example, it would be nice to have a training data structure look like:\n[ [input target] [input target] ... ] Let\u0026rsquo;s go ahead and define that.\n(defn train-data [network data learning-rate] (if-let [[input target] (first data)] (recur (train-network network input target learning-rate) (rest data) learning-rate) network)) Let\u0026rsquo;s try that out on the example earlier\n(def n2 (train-data nn [ [[1 0] [0 1]] [[0.5 0] [0 0.5]] [[0.25 0] [0 0.25] ] ] 0.5)) (ff [1 0] n2) ;=\u0026gt; [0.03765676393050254 0.10552175312900794] Cool. We can now train on data sets. That means we can construct data sets out of infinite lazy sequences too. Let\u0026rsquo;s make a lazy training set of inputs and their inverse.\n(defn inverse-data [] (let [n (rand 1)] [[n 0] [0 n]])) Let\u0026rsquo;s see how well our network is doing after we train it with some more data\n(def n3 (train-data nn (repeatedly 400 inverse-data) 0.5)) (ff [1 0] n3) ;=\u0026gt; [-4.958278484025221E-4 0.8211647699205362] (ff [0.5 0] n3) ;=\u0026gt; [2.1645760787874696E-4 0.5579396715416916] (ff [0.25 0] n3) ;=\u0026gt; [1.8183385523103048E-4 0.31130601296149013] Wow. The more examples it sees, the better that network is doing at learning what to do!\nGeneral Construct Network The only piece that we are missing now is to have a function that will create a general neural network for us. We can choose how many input nerurons, hidden neurons, and output neurons and have a network constructed with random weights.\n(defn gen-strengths [to from] (let [l (* to from)] (map vec (partition from (repeatedly l #(rand (/ 1 l))))))) (defn construct-network [num-in num-hidden num-out] (vec (map vec [(repeat num-in 0) (gen-strengths num-in num-hidden) (repeat num-hidden 0) (gen-strengths num-hidden num-out) (repeat num-out 0)]))) Now we can construct our network from scratch and train it.\n(def tnn (construct-network 2 3 2)) (def n5 (train-data tnn (repeatedly 1000 inverse-data) 0.2)) (ff [1 0] n4) ;=\u0026gt; [-4.954958580800465E-4 0.8160149309699489] And that\u0026rsquo;s it. We have constucted a neural network with core.matrix\nWant more? I put together a github library based on the neural network code in the posts. It is called K9, named after Dr. Who\u0026rsquo;s best dog friend. You can find the examples we have gone through in the tests. There is also an example program using it in the examples directory. It learns what colors are based on thier RGB value.\nThere are a couple web resources I would recommend if you want to look farther as well.\nBasic Network Tutorial Mike Anderson\u0026rsquo;s Clojure Conj talk on Neural Networks Go forth and create Neural Networks!\n","permalink":"https://gigasquidsoftware.com/blog/2013/12/02/neural-networks-in-clojure-with-core.matrix/","summary":"\u003cp\u003eAfter having spent some time recently looking at top-down AI, I\nthought I would spend some time looking at bottom\u0026rsquo;s up AI, machine\nlearning and neural networks.\u003c/p\u003e\n\u003cp\u003eI was pleasantly introduced to \u003ca href=\"https://twitter.com/mikera\"\u003e@mikea\u0026rsquo;s\u003c/a\u003e \u003ca href=\"https://github.com/mikera/core.matrix\"\u003ecore.matrix\u003c/a\u003e at Clojure Conj\nthis year and wanted to try making my own neural network using the\nlibrary. The purpose of this blog is to share my learnings along the\nway.\u003c/p\u003e\n\u003ch2 id=\"what-is-a-neural-network\"\u003eWhat is a neural network?\u003c/h2\u003e\n\u003cp\u003eA neural network is an approach to machine learning that involves\nsimulating, (in an idealized way), the way our brains work on a\nbiological level.  There are three layers to neural network: the input\nlayer, the hidden layers, and the output layer.  Each layer consists\nof neurons that have a value.  In each layer, each neuron is connected to\nthe neuron in the next layer by a connection strength. To get data\ninto the neural network, you assign values to the input layer, (values\nbetween 0 and 1). These values are then \u0026ldquo;fed forward\u0026rdquo; to the hidden layer neurons though an algorithm that\nrelies on the input values and the connection strengths. The values\nare finally \u0026ldquo;fed forward\u0026rdquo; in a similar fashion to the output layer.\nThe \u0026ldquo;learning\u0026rdquo; portion of the neural network comes from \u0026ldquo;training\u0026rdquo; the\nnetwork data.  The training data consists of a collection of\nassociated input values and target values. The training process at a\nhigh level looks like this:\u003c/p\u003e","title":"Neural Networks in Clojure with core.matrix"},{"content":"\nOne of the wonderful things about being a technologist today, is to be part of an industry that is bubbling over with new and exciting things. It can be exhilarating and overwhelming. How can we try and do all these great new things? Of course, it is not sensible to simply drop whatever you are using and continually chase after the newest tech. Nor is steadfastly staying in one place and refusing to accept that there is a better way of doing things. The challenge is to absorb, identify, and synthesize both good of the what we are currently doing and the new stuff too. We want to embrace and continue the good things that are working for us and reach for the new technologies that will propel us farther in the future.\nSince everyone has their own experience synthesizing the world around them, there are many differing opinions on what we should continue to embrace and what we technologies and practices should reach for. I humbly offer my thoughts on this based from my own perspective.\nEmbrace: Agile Feedback Reach for: Lean Startup Discipline and Programmer Anarchy Agile has become a victim of its own success. Becoming so big, its message has been confused and abused in too many ways to name. But the core pillar of frequent and continuous feedback is a foundation to any successful software project and should be embraced. However, we should not stop there. We should reach for the rewards that Lean Startup Methodology offers in the form of displinced validation. We should also reach to unleash the innovation of our smart developers with Programmer Anarchy, and look for ways to ruthlessly stomp out unnecessary and wasteful project management practices.\nEmbrace: Ruby\u0026rsquo;s Community Reach for: Clojure, Go, Elixir, and Meteor Ruby and Rails have been an incredible game changer for web development. But they too are suffering from their own success. One of the strengths of Ruby, which should be embraced and nutured, is the strength of the community and the openness to newcomers. This strength yields a fruitful ground for a vibrant library ecosystem, which has helped Ruby flourish. We need to reach beyond Ruby and Rails to other languages and frameworks that focus on simplicity and concurrency. The bright future will belong to the likes of Clojure, Go, Elixir, and Meteor. We need to reach and start using these in the products we build, while encouraging the growth of a welcoming community and ecosystem like the one we have in Ruby.\nEmbrace: Collaboration Reach for: the Distributed and Decentralized Collaboration with tools like Google Docs works. We should continue to embrace the power that this gives us. However we should embrace tools for combining this collaboration in a truly distributed and decentralized manner. Git itself is wonderful and distributed, but we should reach for tools like Github to be more decentralized and resilient. As privacy concerns grow in today\u0026rsquo;s world. We need to reach beyond the convenience that a centralized source of information gives us and truly understand the trade offs involved.\nWe live in an incredible, vibrant time. Look around and what you do everyday. Embrace and nurture all the good parts, and never give up reaching for something better.\n","permalink":"https://gigasquidsoftware.com/blog/2013/11/02/embrace-and-reach/","summary":"\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/images/posts/ba1fbc99-290760357_01392a3f51_n.jpg\"\u003e\u003c/p\u003e\n\u003cp\u003eOne of the wonderful things about being a technologist today, is\nto be part of an industry that is bubbling over with new and\nexciting things. It can be exhilarating and overwhelming. How can we\ntry and do all these great new things?  Of course, it is not\nsensible to simply drop whatever you are using and continually chase\nafter the newest tech.  Nor is steadfastly staying in one place and\nrefusing to accept that there is a better way of doing things.  The\nchallenge is to absorb, identify, and synthesize both good of the\nwhat we are currently doing and the new stuff too.  We want to embrace and continue the good things that\nare working for us and reach for the new technologies that will propel\nus farther in the future.\u003c/p\u003e","title":"Embrace and Reach"},{"content":"I really love the London. I have only been once many years ago, but I was enchanted. Here is a partial list of my favorite things:\nDucks in Regent\u0026rsquo;s Park Tea Rooms The Food Hall at Harrod\u0026rsquo;s The British Museum English Breakfasts The way the British put an extra \u0026ldquo;r\u0026rdquo; in phrases like \u0026ldquo;vanilla in it\u0026rdquo; As you know, I also adore Clojure. So I am absolutely thrilled to combine the two.\nClojure eXchange I will be speaking at the Clojure eXchange conference on December 6th. The talk is a bit odd, (like me), and will have Clojure, parsers, sea monsters, philosophy, and an AR Drone in it. It should be a lot of fun.\nI really looking forward to get a chance to meet the London Clojure community in person. Hope to see you there.\nP.S. If anyone has any tips on flying overseas with an AR Drone. Please let me know :)\n","permalink":"https://gigasquidsoftware.com/blog/2013/10/03/looking-forward-to-london/","summary":"\u003cp\u003eI really love the London.  I have only been once many years ago,\nbut I was enchanted.  Here is a partial list of my favorite\nthings:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eDucks in Regent\u0026rsquo;s Park\u003c/li\u003e\n\u003cli\u003eTea Rooms\u003c/li\u003e\n\u003cli\u003eThe Food Hall at Harrod\u0026rsquo;s\u003c/li\u003e\n\u003cli\u003eThe British Museum\u003c/li\u003e\n\u003cli\u003eEnglish Breakfasts\u003c/li\u003e\n\u003cli\u003eThe way the British put an extra \u0026ldquo;r\u0026rdquo; in phrases like \u0026ldquo;vanilla in it\u0026rdquo;\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eAs you know, I also adore Clojure. So I am absolutely thrilled to combine the two.\u003c/p\u003e","title":"Looking Forward to London"},{"content":"How to Control Multiple Drones with Clojure The clj-drone library now has multi-drone support! You can now send multiple drones commands, receive their navigation data, and even have them perform their actions autonomously with goals and beliefs.\nIt takes a bit of extra setup to control more than one drone. We need to assign them each an ip and get them talking as an adhoc network. Jim Weirich creating a neat little script to run on the drone to do just this. Here are the instructions:\nChange first drone to adhoc network Connect your computer to the first drone\u0026rsquo;s network.\ntelnet 192.68.1.1 Create the following file as adhoc.sh. This shell script will temporarily change the network to an adhoc network named \u0026ldquo;multidrone_ah\u0026rdquo; and assign it a static ip of 192.168.1.100. The next time you reboot your drone, things will be back to normal.\n; This script should be run on the drone. ; Change the IP address to be difference ; for each drone on the same ad-hoc network ; killall udhcpd ifconfig ath0 down iwconfig ath0 mode ad-hoc essid multidrone_ah channel auto commit ifconfig ath0 192.168.1.100 netmask 255.255.255.0 up Run the script.\nChange the second drone to the adhoc network Connect your computer to the second drone\u0026rsquo;s network.\ntelnet 192.68.1.1 ; This script should be run on the drone. ; Change the IP address to be difference ; for each drone on the same ad-hoc network ; killall udhcpd ifconfig ath0 down iwconfig ath0 mode ad-hoc essid multidrone_ah channel auto commit ifconfig ath0 192.168.1.200 netmask 255.255.255.0 up Run the script.\nOn your laptop Connect to the adhoc network that the drones are on \u0026ldquo;multidrone_ah\u0026rdquo; Change your computer to a static ip on the network (from network preferences on mac) something like 192.168.1.101 Now you are ready to run the program. Here is a small example of sending simple commands:\n(drone-initialize :drone1 \u0026#34;192.168.1.100\u0026#34; default-at-port default-navdata-port) (mdrone :drone1 :take-off) (mdrone :drone1 :land) (drone-initialize :drone2 \u0026#34;192.168.1.200\u0026#34; default-at-port default-navdata-port) (mdrone :drone2 :take-off) (mdrone :drone2 :land) Bring on Multiple Drones interacting with Goals and Beliefs The clj-drone library implements goals and beliefs from John McCarthy\u0026rsquo;s work. The way this works is that the navigation data being constantly sent to our computer for processing. Everytime we get a navigation packet that ends up looking something like this, (but with lots more data):\n{:altitude 0.0, :yaw -0.215, :pitch -1.075, :roll -2.904, :control-state :landed, :communication :ok, :com-watchdog :ok, :seq-num 870} We then define a belief-action using this data.\n(def-belief-action ba-landed1 \u0026#34;I (Drone1) am landed\u0026#34; (fn [{:keys [control-state]}] (= control-state :landed)) (fn [navdata] (mdrone :drone1 :take-off))) The def-belief-action macro takes:\nName of the belief action A readable sentence that expresses the belief. (This is later logged, so that we know what the drone believes at all times.) A predicate that takes in the navigation data as a parameter. When it evaluates to true, then the belief is said to be \u0026ldquo;held\u0026rdquo;. A function to execute when the belief is held The beliefs are then combined to form goals.\n(def-goal g-take-off1 \u0026#34;I (Drone1) want to fly.\u0026#34; (fn [{:keys [control-state]}] (= control-state :hovering)) [ba-landed1 ba-taking-off1]) The def-goal macro takes:\nThe name of the goal A readable sentence that expresses the goal. (This is later logged, so that we can know when it achieves a goal.) A predicate that takes in the navigation data as a parameter. When it evaluates to true, the goal is said to be achieved. It will no longer evaluate or hold any of the belief actions associated with that goal. Finally, we can set a list of goals for a drone to achieve:\n(set-current-goal-list drones :drone1 [g-take-off1 g-find-other-drone-and-wave1 g-land1]) This sets the goal list for a drone. It will take-off, look around for the other drone and wave, (do a dance), once it sees it. Finally, after both drones have spotted each other and waved, they will both land.\nVideo or It Didn\u0026rsquo;t Happen Here is a video of both drones. They will take off, look around for each other and wave when they spot each other. They will land when the have both waved. They are operating solely on goals and beliefs with their navigation data.\nThe code running the video above can be found in the examples of the clj-drone.\nHappy Hacking!\n","permalink":"https://gigasquidsoftware.com/blog/2013/09/05/controlling-multiple-drones-with-clojure-and-goals-and-beliefs/","summary":"\u003ch2 id=\"how-to-control-multiple-drones-with-clojure\"\u003eHow to Control Multiple Drones with Clojure\u003c/h2\u003e\n\u003cp\u003eThe \u003ca href=\"https://github.com/gigasquid/clj-drone\"\u003eclj-drone\u003c/a\u003e library now\nhas multi-drone support!  You can now send multiple drones commands,\nreceive their navigation data, and even have them perform their\nactions autonomously with goals and beliefs.\u003c/p\u003e\n\u003cp\u003eIt takes a bit of extra setup to control more than one drone. We need to assign them each an\nip and get them talking as an adhoc network.\n\u003ca href=\"https://twitter.com/jimweirich\"\u003eJim Weirich\u003c/a\u003e creating a neat little\nscript to run on the drone to do just this.  Here are the\ninstructions:\u003c/p\u003e","title":"Controlling Multiple Drones with Clojure and Goals and Beliefs"},{"content":"Why do you devote time and participate in the community? Why do you devote time and participate in the community? I find joy in coding and making things. I want to be around other people who feel the same way.\nWhy? Because I want to be inspired by others and learn from others and hope that they are inspired and learn from me.\nWhy? Because ideas and learning doesn\u0026rsquo;t happen in a vacuum. There is something magical about the serendipity of human interaction and that needs a community to take place.\nWhy? It is all fundamentally about people. People dream. We talk about our dreams and get together and make them reality. That is the magic of our civilization.\nWhy? I don\u0026rsquo;t want to dream alone.\nWhat are your reasons? In response to Let\u0026rsquo;s Start with Why\n","permalink":"https://gigasquidsoftware.com/blog/2013/07/22/my-5-whys-of-community/","summary":"\u003ch2 id=\"why-do-you-devote-time-and-participate-in-the-community\"\u003eWhy do you devote time and participate in the community?\u003c/h2\u003e\n\u003col\u003e\n\u003cli\u003e\u003cem\u003eWhy do you devote time and participate in the community?\u003c/em\u003e\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003eI find joy in coding and making things. I want to be around other\npeople who feel the same way.\u003c/p\u003e\n\u003col start=\"2\"\u003e\n\u003cli\u003e\u003cem\u003eWhy?\u003c/em\u003e\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003eBecause I want to be inspired by others and learn from others and hope that they are inspired and learn from me.\u003c/p\u003e\n\u003col start=\"3\"\u003e\n\u003cli\u003e\u003cem\u003eWhy?\u003c/em\u003e\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003eBecause ideas and learning doesn\u0026rsquo;t happen in a vacuum. There is something magical about the serendipity of human interaction and that needs a community to take place.\u003c/p\u003e","title":"My 5 Whys of Community"},{"content":"Lately, I have had the pleasure of speaking and sharing my experience of programming AR Drones with Clojure. However, doing live hardware demos has not always been a smooth ride. In fact, it can be fraught with peril. I thought that I would share some of the tips and tricks that have helped me, as well as help make you aware of some potential pitfalls.\nTraveling with the AR Drone Do you need to take your drone with you on the plane to the demo? The box that the drone comes in is a very nice carrying case, however it is too big to take on as a carry-on. I found that taking the hull off, and packing it into a plastic box worked well. It was small enough to pack under the seat of even the smaller planes. I took the battery out and packed it in my checked luggage.\nBefore the Demo Put colored masking tape on the floor : If the floor is featureless, the drone will have a hard time staying in one place while it is hovering. Put down some strips of colored masking tape in the area that you want to demo the drone.\nCharge the spare battery: Make sure that you have at least 2 batteries charged and ready to go. If there is an extra plug nearby, just plug in the battery and charger until you are ready to present.\nBeware the network interference: In some larger venues, like hotels, the network traffic will make things break. In particular, receiving navigation data back from the drone. There are possible strategies for mitigating this - the only one I have tried so far is to bump up the timeout on the UDP connection. Other things that you may want to try would be to auto-reconnect after timeout. Also limiting the amount navdata you need might also work.\nBackup videos - Having backup videos of your demo actually working is essential. It is safety net that will allow you to sleep the night before. Like they say, \u0026ldquo;Hope for the best, but plan for the worst\u0026rdquo;.\nRehearse - If possible, go through your drone demos in the space sometime before the talk. You will get a feeling for issues that might occur - like network troubles.\nDemo Time! Front row drone catchers - Enlist the aid of your audience. Show the people in the front row how to catch a drone safely and hold it at a 90 degree angle so the engine cuts out. That way, if the drone starts going off in unplanned ways, you will have help.\nCross your fingers and have fun - Good luck. Hardware demos are a lot of fun. Hopefully, everything we work as planned, but if not - at least it was interesting.\n","permalink":"https://gigasquidsoftware.com/blog/2013/07/15/demoing-with-drones-tips-and-warnings/","summary":"\u003cp\u003eLately, I have had the pleasure of speaking and sharing my experience\nof programming \u003ca href=\"http://ardrone2.parrot.com/\"\u003eAR Drones\u003c/a\u003e with Clojure.  However, doing live hardware\ndemos has not always been a smooth ride.  In fact, it can be fraught\nwith peril.  I thought that I would share some of the tips and tricks\nthat have helped me, as well as help make you\naware of some potential pitfalls.\u003c/p\u003e\n\u003ch2 id=\"traveling-with-the-ar-drone\"\u003eTraveling with the AR Drone\u003c/h2\u003e\n\u003cfigure class=\"left\"\u003e\n    \u003cimg loading=\"lazy\" src=\"/images/posts/4537bc03-9301848814_1633857d6d.jpg\"/\u003e \n\u003c/figure\u003e\n\n\u003cp\u003eDo you need to take your drone with you on the plane to the demo?\nThe box that the drone comes in is a very nice carrying case, however it\nis too big to take on as a carry-on.  I found that taking the hull\noff, and packing it into a plastic box worked well.  It was small\nenough to pack under the seat of even the smaller planes.  I took the\nbattery out and packed it in my checked luggage.\u003c/p\u003e","title":"Demoing with Drones: Tips and Warnings"},{"content":"\nPhoto by Mike Bridge @michaelbridge\nI started off as a professional ballet dancer, studied Physics in college, and ended up as a Software Developer.\nMy current tech interests are Clojure, AI, and Robots.\nWhen I am left to daydream, I think of the dynamics of flocks of birds, what the Giant Squids might really be doing down there in the deep, and maybe opening a first-rate cheese shop one day.\nGithub LinkedIn ","permalink":"https://gigasquidsoftware.com/about/","summary":"\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/images/about-photo.jpg\"\u003e\u003c/p\u003e\n\u003cp\u003e\u003cem\u003ePhoto by Mike Bridge \u003ca href=\"https://twitter.com/michaelbridge\"\u003e@michaelbridge\u003c/a\u003e\u003c/em\u003e\u003c/p\u003e\n\u003cp\u003eI started off as a professional ballet dancer, studied Physics in college, and ended up as a Software Developer.\u003c/p\u003e\n\u003cp\u003eMy current tech interests are Clojure, AI, and Robots.\u003c/p\u003e\n\u003cp\u003eWhen I am left to daydream, I think of the dynamics of flocks of birds, what the Giant Squids might really be doing down there in the deep, and maybe opening a first-rate cheese shop one day.\u003c/p\u003e","title":"About"},{"content":" I am the author of Living Clojure by O\u0026rsquo;Reilly. It is both an introduction and training plan for developers to learn Clojure.\nThe writing of the booking was inspired after being introduced to a running program called Ease into 5K. Before trying the program, I had tried running on my own. Each time, I ended up quitting before too long. I thought that I just wasn\u0026rsquo;t cut out for running. But in reality, I tried to do too much too fast. After hearing someone say that they had tried to pick up Clojure over the weekend, didn\u0026rsquo;t get too far, and didn\u0026rsquo;t think Clojure was for them, I made the connection. Doing too much too fast, isn\u0026rsquo;t only a problem with learning to run, but also a problem with learning programming languages. The reason I had finally succeeded with running was that I gradually worked myself up over a course of seven weeks. The book also follows this methodology. The first half of the book is a guided introduction to Clojure and some of its key libraries. The second half of the book is a structured set of daily exercises over a course of seven weeks that will give your brain a gradual doses of functional programming that will have you living Clojure at the end.\nCode Shifter Twelve year old Eliza discovers she has the power to change a machine’s code just by touch. When the government’s evil artificial intelligence takes her brother away, she uses her new ability to fight back. Now she\u0026rsquo;s on the run as an outlaw and her only hope to save him is to find the Underground Programmer’s Academy. She needs to learn how to control her powers and fast. If she doesn’t get her brother back in time, his brain could be scrambled forever.\nTogether, with her friends, Eliza sets out on an adventure that involves learning code, fighting robots, and finding out how strong she can be.\nhttp://www.codeshifterbook.com/\n","permalink":"https://gigasquidsoftware.com/books/","summary":"\u003cfigure\u003e\u003ca href=\"http://shop.oreilly.com/product/0636920034292.do?sortby=publicationDate\"\u003e\n    \u003cimg loading=\"lazy\" src=\"/images/living-clojure-cover.gif\"/\u003e \u003c/a\u003e\n\u003c/figure\u003e\n\n\u003cp\u003eI am the author of \u003ca href=\"http://shop.oreilly.com/product/0636920034292.do?sortby=publicationDate\"\u003eLiving Clojure\u003c/a\u003e by O\u0026rsquo;Reilly.  It is both an introduction and\ntraining plan for developers to learn Clojure.\u003c/p\u003e\n\u003cp\u003eThe writing of the booking was inspired\nafter being introduced to a running program called \u003cem\u003eEase into 5K\u003c/em\u003e.\nBefore trying the program, I had tried running on my own.  Each time,\nI ended up quitting before too long.  I thought that I just wasn\u0026rsquo;t cut\nout for running.  But in reality, I tried to do \u003cem\u003etoo much too\nfast\u003c/em\u003e.  After hearing someone say that they had tried to pick up\nClojure over the weekend, didn\u0026rsquo;t get too far, and didn\u0026rsquo;t think Clojure\nwas for them,  I made the connection.  Doing \u003cem\u003etoo much too fast\u003c/em\u003e,\nisn\u0026rsquo;t only a problem with learning to run, but also a problem with\nlearning programming languages.  The reason I had finally succeeded\nwith running was that I gradually worked myself up over a course of\nseven weeks.  The book also follows this methodology.  The first half\nof the book is a guided introduction to Clojure and some of its key\nlibraries.  The second half of the book is a structured set of daily\nexercises over a course of seven weeks that will give your brain a\ngradual doses of functional programming that will have you \u003cem\u003eliving\u003c/em\u003e\nClojure at the end.\u003c/p\u003e","title":"Books"},{"content":"\nPhoto by Mike Bridge @michaelbridge\nI also enjoy talking and sharing my various enthusiams, which seem to be Clojure, Robots, and AI lately.\nUpcoming Talks Past Talks Clojure Conj 2024 - Real World AI Integration Clojure Conj 2023 - Vector Symbolic Architectures in Clojure Clojure Conj 2018 - Can you GAN? Craft Conf 2018 - Unconvential Programming with Chemical Computing Clojure Conj 2017 - Deep Learning Needs Clojure Velocity Conf NY 2017 - Unconventional Programming Paradigms for the Future Now Joy of Coding - June 2017 The Joy of Gradient Descent Ohio DevFest 2016 How to Train Your Computer to Talk To You EuroClojure 2016 Genetic Programming and Beyond with clojure.spec GeeCon 2016 Clojure, clojure.spec, and Beyond Strange Loop 2015: Unconventional Programming with Chemical Computing OSCON 2015 - A workshop Solving the Concurrency Problem with Clojure and also a talk Unconventional Programming with Chemical Computing. The schedule details are here Strange Loop 2014: Our Shared Joy of Programming Solid Con 2014 Keynote: Real Time Robot Dance Party Code Mesh 2013: The Joy of Flying Robots with Clojure Clojure Exchange 2013: Learning to talk to machines with speech acts - a shipwreck adventure Clojure Conj 2013: Learning to talk to machines with speech acts - a shipwreck adventure OSCON 2013 Keynote: [The Joy of Flying Robots with Clojure](https://www.youtube.com/watch?v= Ty9QDqV-_Ak) Lambda Jam 2013: The Joy of Flying Robots with Clojure Clojure West 2012: Why is a Monad like a Writing Desk? CodeMash 2012: A Fairy Tale in Clojure JRubyConf 2011: Semantic Web with JRuby ","permalink":"https://gigasquidsoftware.com/speaking/","summary":"\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/images/speaking-photo.jpg\"\u003e\u003c/p\u003e\n\u003cp\u003e\u003cem\u003ePhoto by Mike Bridge \u003ca href=\"https://twitter.com/michaelbridge\"\u003e@michaelbridge\u003c/a\u003e\u003c/em\u003e\u003c/p\u003e\n\u003cp\u003eI also enjoy talking and sharing my various enthusiams, which seem to\nbe Clojure, Robots, and AI lately.\u003c/p\u003e\n\u003ch2 id=\"upcoming-talks\"\u003eUpcoming Talks\u003c/h2\u003e\n\u003ch2 id=\"past-talks\"\u003ePast Talks\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"https://www.youtube.com/watch?v=oXlb1mITJHA\"\u003eClojure Conj 2024 - Real World AI Integration\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://www.youtube.com/watch?v=ByzaFEVlaq0\u0026amp;t=8s\"\u003eClojure Conj 2023 - Vector Symbolic Architectures in Clojure\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://www.youtube.com/watch?v=yzfnlcHtwiY\"\u003eClojure Conj 2018 - Can you GAN?\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://craft-conf.com/\"\u003eCraft Conf 2018 - Unconvential Programming with Chemical Computing\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://www.youtube.com/watch?v=eLl6_k_fZn4\"\u003eClojure Conj 2017 - Deep Learning Needs Clojure\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://conferences.oreilly.com/velocity/vl-ny\"\u003eVelocity Conf NY 2017 - Unconventional Programming Paradigms for the Future Now\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"http://joyofcoding.org/\"\u003eJoy of Coding - June 2017\u003c/a\u003e The Joy of Gradient Descent\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://ohiodevfest.com/\"\u003eOhio DevFest 2016\u003c/a\u003e How to Train Your Computer to Talk To You\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"http://euroclojure.org/\"\u003eEuroClojure 2016\u003c/a\u003e \u003ca href=\"https://www.youtube.com/watch?v=xvk-Gnydn54\u0026amp;t=7s\"\u003eGenetic Programming and Beyond with clojure.spec\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"http://2016.geecon.cz\"\u003eGeeCon 2016\u003c/a\u003e Clojure, clojure.spec, and Beyond\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://thestrangeloop.com/\"\u003eStrange Loop 2015\u003c/a\u003e: \u003ca href=\"https://www.youtube.com/watch?v=cHoYNStQOEc\"\u003eUnconventional Programming with Chemical Computing\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"http://www.oscon.com/open-source-2015\"\u003eOSCON 2015\u003c/a\u003e - A workshop \u003cem\u003eSolving the Concurrency Problem with Clojure\u003c/em\u003e and also a talk \u003cem\u003eUnconventional Programming with Chemical Computing\u003c/em\u003e. The schedule details are \u003ca href=\"http://www.oscon.com/open-source-2015/public/schedule/speaker/154757\"\u003ehere\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://thestrangeloop.com/\"\u003eStrange Loop 2014\u003c/a\u003e: \u003ca href=\"https://www.youtube.com/watch?v=3_zW63dcZB0\"\u003eOur Shared Joy of Programming\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003eSolid Con 2014 Keynote: \u003ca href=\"https://www.youtube.com/watch?v=sHK4v5MimJs\"\u003eReal Time Robot Dance Party\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"http://codemesh.io/\"\u003eCode Mesh 2013\u003c/a\u003e: The Joy of Flying Robots with Clojure\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"http://skillsmatter.com/event/java-jee/clojure-exchange-2013\"\u003eClojure Exchange 2013\u003c/a\u003e: Learning to talk to machines with speech acts - a shipwreck adventure\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"http://clojure-conj.org/\"\u003eClojure Conj 2013\u003c/a\u003e: Learning to talk to\nmachines with speech acts - a shipwreck adventure\u003c/li\u003e\n\u003cli\u003eOSCON 2013 Keynote: [The Joy of Flying Robots with Clojure](\u003ca href=\"https://www.youtube.com/watch?v=\"\u003ehttps://www.youtube.com/watch?v=\u003c/a\u003e Ty9QDqV-_Ak)\u003c/li\u003e\n\u003cli\u003eLambda Jam 2013: \u003ca href=\"http://www.infoq.com/presentations/clojure-robots\"\u003eThe Joy of Flying Robots with Clojure\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003eClojure West 2012: \u003ca href=\"http://www.infoq.com/presentations/Why-is-a-Monad-Like-a-Writing-Desk\"\u003eWhy is a Monad like a Writing Desk?\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003eCodeMash 2012: \u003ca href=\"http://www.slideshare.net/gigasquidcm/fairy-taleclojure\"\u003eA Fairy Tale in Clojure\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003eJRubyConf 2011:\n\u003ca href=\"https://github.com/gigasquid/Presentations/blob/master/SemanticWebJRuby.pdf\"\u003eSemantic Web with JRuby\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e","title":"Speaking"},{"content":"\nPreface: A Gentle Obsession About a year ago, I picked up John McCarthy\u0026rsquo;s paper on Elephant 2000. I have to admit that I only understood about 10% of it. But I was so intrigued by the ideas that it sent me on a quest. I re-read it numerous times, slept with it under my pillow, and finally decided that I needed to read his other papers to get an insight into his thoughts. I began a considered effort with Seven McCarthy Papers in Seven Weeks. It ended up taking about three months, rather than seven 7 weeks. Again I came back to Elephant 2000. I began to understand more as other ideas and concepts sunk in, like ascribing beliefs and goals to machines. But to really explore the ideas, I really wanted to try to implement parts of Elephant in my own programming language. The problem was, having no formal training in computer science, (my background is Physics), I had never created a programming language before. The stars aligned and I found the Instaparse Clojure library. The result is Babar, a language designed to explore communication with machines via Speech Acts.\nWhat are the Speech Acts? When I say say \u0026ldquo;Pass the salt.\u0026rdquo;, the meaning behind the utterance is that I would like someone to reach out and move the salt shaker to me. I am requesting an action be performed. It doesn\u0026rsquo;t really matter if the utterance is in English, French, or Spanish. The intention is the same. Furthermore, if you accept my request to pass the salt. It creates a commitment on your part to actually perform the action. There are two types of speech acts that Babar is concerned with. The first is called an Illocutionary Act. Some of the english verbs denoting these acts are \u0026ldquo;assert\u0026rdquo;, \u0026ldquo;command\u0026rdquo;, \u0026ldquo;request\u0026rdquo;, and \u0026ldquo;query\u0026rdquo;. The second is a Perlocutionary Act. These are acts that are concerned with the effects of hearing them on future actions. Some of english verbs denoting these acts are \u0026ldquo;convince\u0026rdquo;, \u0026ldquo;persuade\u0026rdquo;, and \u0026ldquo;warn\u0026rdquo;.\nHello Babar Babar is an experimental language that uses these Speech Acts to communicate. It also combines one of the other ideas of McCarthy, that is of beliefs and goals. The ultimate aim in the language is discover ways of thinking about computers and communicating with them based on the way that we communicate with each other. The state of a computer at any given point in time can be very complex and hard to understand. If we ascribe this state to be a \u0026ldquo;belief\u0026rdquo;, it becomes easier to understand and thus easier to program. The Babar REPL has internal commitments and internal beliefs. The goal of the Babar REPL is to keep all of its commitments. Speech acts are used to \u0026ldquo;convince\u0026rdquo; Babar of beliefs and to make \u0026ldquo;requests\u0026rdquo; that form commitments. The Babar REPL continually checks to see if it needs to fulfill a commitments. It fulfills them based on its beliefs. As an optional configuration, the REPL will speak aloud its beliefs as the become true - or as it \u0026ldquo;holds\u0026rdquo; the belief.\nSyntax and Basics The language uses basic Clojure datatypes and makes the parens optional in most cases to make the expressions look more like syntactically sugared speech acts.\n1 ;=\u0026gt; 1 2.3 ;=\u0026gt; 2.3 -3.4 ;=\u0026gt; 3.4 \u0026#34;cat\u0026#34; ;=\u0026gt; cat :bird ;=\u0026gt; bird true ;=\u0026gt; true {:cat :meow :dog :bark} ;=\u0026gt; {:cat :meow :dog :bark} [1 2 true :bird] ;=\u0026gt; [1 2 true bird] atom 1 ;=\u0026gt; # (def dog 16) dog ;=\u0026gt; 16 def cat 18 cat ;=\u0026gt; 18 Vectors are a bit interesting in the respect that you don\u0026rsquo;t need to input the square brackets. If you just put in space delimited items, it will automatically construct a vector for you.\n1 2 3 4 ;=\u0026gt; [1 2 3 4] You can create anonymous functions with the fn [x] syntax from clojure. And call them with surrounding parens. You can call regular functions by the () notation or the shorthand :.\nfn [x] + x 1 ;=\u0026gt; fn (fn [x] + x 1) ;=\u0026gt; fn ((fn [x] + x 1) 3) ;=\u0026gt; 4 ((fn [x y z] + x y z) 1 2 3) ;=\u0026gt; 6 ((fn [] [4 5 6])) ;=\u0026gt; [4 5 6] defn dog [] \u0026#34;woof\u0026#34; dog: ;=\u0026gt; \u0026#34;woof\u0026#34; To see the complete documentation - please visit the Github repo.\nShow Me Babar Speech Acts Now that we have the basics. Let\u0026rsquo;s look at example of running a program with speech acts. This one speaks its beliefs and has assertions, a request, and queries.\nspeak-config true. assert sunny false. convince #nice-day \u0026#34;It is a nice day.\u0026#34; fn [] = sunny true. request *open-window when #nice-day fn [] println \u0026#34;Opened the window\u0026#34;. query request-is-done *open-window? assert sunny true. query request-is-done *open-window? Here is another one that shows using a request until a belief is held.\nspeak-config true. assert counter atom 1. convince #done \u0026#34;I am done counting\u0026#34; fn [] \u0026gt; @counter 3. request *count-up until #done fn [] swap! counter inc. sleep 25. query request-value *count-up? Here the REPL asks you a question if you give it an undeclared var\nspeak-config true. ask-config true. request *task1 fn [] + 10 x. query request-is-done *task1? assert x 3. sleep 10. query request-is-done *task1? query request-value *task1? Autonomous AR Drone Flight with Babar REPL Since the language is aimed at communincating with machines. It is only natural that I use it to talk to the AR Drone. Here is a program that has the drone take off, get to a cruising altitude, and land - all using speech acts (and the clj-drone library).\nspeak-config true. import \u0026#34;clj-drone.core\u0026#34;. import \u0026#34;clj-drone.navdata\u0026#34;. assert get-navdata [key] get @nav-data key. assert navdata-equal [key val] = (get-navdata key) val. assert navdata-gt [key val] \u0026gt; (get-navdata key) val. assert init-drone [] (drone-initialize). assert init-nav [] (drone-init-navdata). convince #landed \u0026#34;I am on the ground\u0026#34; fn [] (navdata-equal :control-state :landed). convince #flying \u0026#34;I am flying\u0026#34; fn [] or (navdata-equal :control-state :flying) (navdata-equal :control-state :hovering). convince #high-enough \u0026#34;I am high enough\u0026#34; fn [] (navdata-gt :altitude 1.5). request *take-off when #landed fn [] (drone :take-off). request *cruising-alt when #flying until #high-enough fn [] (drone :up 0.1). request *land when #high-enough fn [] (drone :land). convince #done \u0026#34;Whee! I am done.\u0026#34; fn [] and (navdata-equal :control-state :landed) query request-is-done *land. request *end-navstream when #done fn [] (end-navstream). Conclusion and Thanks I can honestly say, that this has been one of the most enjoyable programming quests. I encourage you all to look at McCarthy\u0026rsquo;s papers, Clojure, Instaparse, and of course, hacking robots. A special thanks to all the Cincy folks at Neo who have supported me through my gentle obsessions and have let me have the freedom to follow my curiosity.\n","permalink":"https://gigasquidsoftware.com/blog/2013/06/04/babar-a-little-language-with-speech-acts-for-machines/","summary":"\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/images/posts/0adcb141-9925781735_77dfa3157b_o.jpg\"\u003e\u003c/p\u003e\n\u003ch2 id=\"preface-a-gentle-obsession\"\u003ePreface: A Gentle Obsession\u003c/h2\u003e\n\u003cp\u003eAbout a year ago, I picked up John McCarthy\u0026rsquo;s paper on \u003ca href=\"http://web.archive.org/web/20131014084908/http://www-formal.stanford.edu/jmc/elephant/elephant.html\"\u003eElephant 2000\u003c/a\u003e. I have to admit that I only understood about 10% of it. But I was so intrigued by the ideas that it sent me on a quest. I re-read it numerous times, slept with it under my pillow, and finally decided that I needed to read his other papers to get an insight into his thoughts. I began a considered effort with \u003ca href=\"http://gigasquidsoftware.com/blog/2012/09/18/7-john-mccarthy-papers-in-7-days-prologue/\"\u003eSeven McCarthy Papers in Seven Weeks\u003c/a\u003e. It ended up taking about three months, rather than seven 7 weeks. Again I came back to Elephant 2000. I began to understand more as other ideas and concepts sunk in, like \u003ca href=\"http://web.archive.org/web/20131014084908/http://www-formal.stanford.edu/jmc/ascribing/ascribing.html\"\u003eascribing beliefs and goals to machines\u003c/a\u003e. But to really explore the ideas, I really wanted to try to implement parts of Elephant in my own programming language. The problem was, having no formal training in computer science, (my background is Physics), I had never created a programming language before. The stars aligned and I found the \u003ca href=\"https://github.com/Engelberg/instaparse\"\u003eInstaparse\u003c/a\u003e Clojure library. The result is \u003ca href=\"https://github.com/gigasquid/babar\"\u003eBabar\u003c/a\u003e, a language designed to explore communication with machines via \u003ca href=\"http://en.wikipedia.org/wiki/Speech_act\"\u003eSpeech Acts\u003c/a\u003e.\u003c/p\u003e","title":"Babar - A Little Language with Speech Acts for Machines"},{"content":"Creating your own programming language with Clojure and Instaparse is like building rainbows with s-expressions. The Instaparse library is an elegant way of building executable parsers trees with pattern matching and standard EBNF notation for context-free grammars. Since this is my first foray into parser trees and grammars, I thought I would share my learnings in this post.\nStarting with a Single Word Let\u0026rsquo;s start with the simplest example: a number. When we start up our REPL in our brand new language, we want to be able to enter an integer, and have evaluate as an integer.\nMyCoolLang\u0026gt; 1 1 Using the instaparse library, we define a number to be a regex matching an integer.\n(ns coollang.parser (:require [instaparse.core :as insta])) (def parser (insta/parser \u0026#34;number = #\u0026#39;[0-9]+\u0026#39;\u0026#34;)) (parser \u0026#34;1\u0026#34;) ;=\u0026gt;; [:number \u0026#34;1\u0026#34;] We now have a parser tree node that is of a type number. Pretty nice so far, but more rainbows are coming. You can make elegant transformations on the parser tree, and does them in a bottom up fashion, so you can use it for evaluation as well. In our simple number example, we are applying the read-string function on the :number node to turn it into a int.\n(def transform-options {:number read-string}) (defn parse [input] (-\u0026gt;\u0026gt; (parser input) (insta/transform transform-options))) (parse \u0026#34;1\u0026#34;) ;=\u0026gt; 1 Adding on spaces and vectors Let\u0026rsquo;s build on a bit more. When someone enters in a sequence of numbers separated by spaces, it will be defined as a vector.\nMyCoolLang\u0026gt; 1 2 3 4 [1 2 3 4] We need to add the notion of spaces, spaces with numbers, and vectors into our grammar, as well as the rules for evaluating these new nodes. Notice that we use the \u0026lt;\u0026gt; notation to hide the definition in the parser tree. The + means one or more times. The * means 0 or more times, and the | means or.\n(def parser (insta/parser \u0026#34;expr = number | vector vector = snumber+ number \u0026lt;snumber\u0026gt; = (number space)* \u0026lt;space\u0026gt; = \u0026lt;#\u0026#39;[ ]+\u0026#39;\u0026gt; number = #\u0026#39;[0-9]+\u0026#39;\u0026#34;)) (parser \u0026#34;1 2 3 4\u0026#34;) ;=\u0026gt; [:expr [:vector [:number \u0026#34;1\u0026#34;] [:number \u0026#34;2\u0026#34;] [:number \u0026#34;3\u0026#34;] [:number \u0026#34;4\u0026#34;]]] (def transform-options {:number read-string :vector (comp vec list) :expr identity}) (defn parse [input] (-\u0026gt;\u0026gt; (parser input) (insta/transform transform-options))) (parse \u0026#34;1 2 3 4\u0026#34;) ;=\u0026gt; [1 2 3 4] Adding in operations Pretty cool. We have numbers and vectors. Let\u0026rsquo;s see if we can do something fun like do some simple math on these vectors or numbers. We want it so when we type in + and some numbers, it adds them up.\nMyCoolLang\u0026gt; + 1 2 3 4 10 Of course we need to further expand our grammar and rules.\n(def parser (insta/parser \u0026#34;expr = number | vector | operation operation = operator space+ vector operator = \u0026#39;+\u0026#39; | \u0026#39;-\u0026#39; | \u0026#39;*\u0026#39; | \u0026#39;/\u0026#39; vector = snumber+ number \u0026lt;snumber\u0026gt; = (number space)* \u0026lt;space\u0026gt; = \u0026lt;#\u0026#39;[ ]+\u0026#39;\u0026gt; number = #\u0026#39;[0-9]+\u0026#39;\u0026#34;)) (parser \u0026#34;+ 1 2 3 4\u0026#34;) ;=\u0026gt; [:expr ; [:operation ; [:operator \u0026#34;+\u0026#34;] ; [:vector [:number \u0026#34;1\u0026#34;] [:number \u0026#34;2\u0026#34;] [:number \u0026#34;3\u0026#34;] [:number \u0026#34;4\u0026#34;]]] (defn choose-operator [op] (case op \u0026#34;+\u0026#34; + \u0026#34;-\u0026#34; - \u0026#34;*\u0026#34; * \u0026#34;/\u0026#34; /)) (def transform-options {:number read-string :vector (comp vec list) :operator choose-operator :operation apply :expr identity}) (defn parse [input] (-\u0026gt;\u0026gt; (parser input) (insta/transform transform-options))) (parse \u0026#34;+ 1 2 3 4\u0026#34;) ;=\u0026gt; 10 Add a REPL All we need now is a cool REPL to start working in: We just need a main function to call our REPL, (Read - Evaluate - Print - Loop), and we are all set.\n(ns coollang.repl (:require [coollang.parser :as parser])) (defn repl [] (do (print \u0026#34;MyCoolLang\u0026gt; \u0026#34;) (flush)) (let [input (read-line)] (println (parser/parse input)) (recur))) (defn -main [\u0026amp; args] (println \u0026#34;Hello MyCoolLang!\u0026#34;) (println \u0026#34;===============\u0026#34;) (flush) (repl)) Closing and Inspiration I have enjoyed playing around and learning about creating programming languages with Clojure and instaparse. It truly is a beautiful library. If you need any more inspiration to start creating your own programming language, may I recommend:\nGrowing a Program Language by Guy Steele - A classic and amazing talk about designing programming languages.\nBODOL - A language experiment using Clojure and Instaparse\nNow go forth and create!\n","permalink":"https://gigasquidsoftware.com/blog/2013/05/02/growing-a-language-with-clojure-and-instaparse/","summary":"\u003cp\u003eCreating your own programming language with Clojure and \u003ca href=\"https://github.com/Engelberg/instaparse\"\u003eInstaparse\u003c/a\u003e is like building rainbows with s-expressions.  The Instaparse library is an elegant way of building executable parsers trees with pattern matching and \u003ca href=\"http://en.wikipedia.org/wiki/Extended_Backus%E2%80%93Naur_Form\"\u003e\u003cem\u003estandard EBNF notation\u003c/em\u003e\u003c/a\u003e for context-free grammars. Since this is my first foray into parser trees and grammars, I thought I would share my learnings in this post.\u003c/p\u003e\n\u003ch2 id=\"starting-with-a-single-word\"\u003eStarting with a Single Word\u003c/h2\u003e\n\u003cp\u003eLet\u0026rsquo;s start with the simplest example:  a number.  When we start up our REPL in our brand new language, we want to be able to enter an integer, and have evaluate as an integer.\u003c/p\u003e","title":"Growing a Language with Clojure and Instaparse"},{"content":"So I am in the midst of doing something a bit crazy and a bit wonderful at the same time. I am opening a coworking space in Loveland, OH called Locolo. It is a bit crazy because it has very little chance of being profitable, I have very little free time in my life to devote to such an undertaking, and I work full-time with awesome folks so I wouldn\u0026rsquo;t even be there during the day. Despite these very pragmatic reasons for not doing it, somewhere along the way I said F*** IT, I am doing it anyway. This blog post is an attempt to explain why.\nI want a coworking space to exist. Coworking has changed my life. About three years ago, I became independent and starting doing development work out of my house. I found myself feeling increasingly lonely and isolated, working alone at my kitchen table day after day. I heard of a coworking space close to downtown called Cincy CoWorks, started by the visionaries Gerard Sychay and Bill Barnett. I joined and started going down there to work a few days a week. It was wonderful. Work became fun again. They day was peppered with serendipitous encounters and conversations the sparked my imagination and curiosity. I got involved in the Ruby community, usergroups, and eventually became part of the EdgeCase (and now Neo) company that makes me happy every day. In fact, the people that I met coworking are still an important part of my life today. So when I heard that Cincy Coworks suspended operations, I was a bit sad. I was sad that there was no longer an environment where the coworking magic could live. I had a small thought germinate in the back of my head then, that I would like to open a coworking space one day.\nSomeone told me it could not be done. Sometimes there are clear catalysts in life. For me, it was someone telling me that a successful coworking space in Cincinnati could not be done. They may be right. I don\u0026rsquo;t know. But I do know, that the moment I heard that, something changed. I have this little part of me that can\u0026rsquo;t stand it when someone tells me I can\u0026rsquo;t do something. In fact, it is most likely one of the reasons that went into software development in the first place. That little part of me went a grabbed that small thought about starting a coworking place and dragged it out to the front where I couldn\u0026rsquo;t ignore it any more and said - DO IT.\nA Lean Experiment Serendipity happens. I had just finished reading Eric Ries\u0026rsquo;s book, The Lean Startup. It is a great book and highly recommend it. The main idea is using scientific methods for businesses. It got me thinking about what a coworking MVP, (minimun viable product), would be. I started looking around at spaces in Loveland just for fun, and stumbled into to one that would be perfect. I discovered The Loveland Art Studios on Main, a old school building turned into mostly art studios, but also housed a gym, spinning center, and training field for kids. The rent was very reasonable, had a 6 month lease, and already had wifi throughout the building. It was too perfect to pass up. I defined a hypothesis and experiment on the spot.\nHypothesis: There are enough people in the North and East part of Cincinnati interested to support a self-sustaining coworking space. Experiment: Open a small coworking space for 6 months Metrics: Monthly income - Monthly expenses\nIf at the end of the 6 months, the hypothesis is proven incorrect, I will accept my outcome and close up shop. However, even if the experiment is not successful, I will be capturing metrics on this and other experiments to save as artifacts to share with others that come after me. Hopefully, it will make it better and easier for the next person to launch coworking spaces. If you are interested in monthly updates on my metrics and experiments, ping me, and I will happily add you to my monthly distribution list.\nDoing something you believe in I don\u0026rsquo;t think this part needs much explaining. Doing something you believe in is worthwhile just in itself. Enough said.\nGetting involved in the community is magic Starting up a coworking space is all about building community. The very act of building something together creates magic. I am so thankful for all the people that have pitched in a helped me with their advice, encouragement, and assistance so far. Shout outs to Bill Barnett, Gerard Sychay, Paul Heinrich, Jacki Keys, Elizabeth Naramore, Chris Moore, Rob Biederhorn, Mason Stewart, and others. You all rock. really.\nAn Excuse for a Biscuit Tasting One of the fun perks of running a coworks is you get to have Open Houses and other excuses to eat biscuits. When I say \u0026ldquo;biscuits\u0026rdquo;, I mean biscuits in the British form, that translates into American as \u0026ldquo;delicious cookies\u0026rdquo;. So if you are in Cincinnati, sign up for the Open House of Locolo. Where you can not only see the space and meet awesome people, but also rate various cookies on important factors such as dunkablility and crunchiness.\nThanks \u0026amp; Toodles for now,\nCarin\n","permalink":"https://gigasquidsoftware.com/blog/2013/03/14/why-open-a-coworking-space/","summary":"\u003cp\u003eSo I am in the midst of doing something a bit crazy and a bit wonderful at the same time. I am opening a coworking space in Loveland, OH called \u003ca href=\"http://locolo.us/\"\u003eLocolo\u003c/a\u003e. It is a bit crazy because it has very little chance of being profitable, I have very little free time in my life to devote to such an undertaking, and I work full-time with awesome folks so I wouldn\u0026rsquo;t even be there during the day. Despite these very pragmatic reasons for not doing it, somewhere along the way I said F*** IT, I am doing it anyway. This blog post is an attempt to explain why.\u003c/p\u003e","title":"Why Open a Coworking Space?"},{"content":"Clojure is fun. Flying AR Parrot Drones are fun. Put them together and there is pure joy.\nEver since I found out that you could program and control your drone over UDP, I couldn\u0026rsquo;t wait to try it out in Clojure. I had dreams of controlling it with my Emacs REPL. That dream came true and it has been a true joy to fly in a function language. This blog post shows some of the features that the clj-drone project has so far. There is still a bit of work to go to make it complete. But, I wanted to share and hopefully encourage others to start playing with it too.\nThe Simple Take-off and Landing (ns clj-drone.example.simple (:require [clj-drone.core :refer :all])) (drone-initialize) ;Use ip and port for non-standard drone ip/port ;(initialize ip port) (drone :take-off) (Thread/sleep 10000) (drone :land) Here is a video of executing the entire program in nrepl/ emacs\nControlling the Drone with Emacs/ Clojure REPL Running the program all at once to control the drone is fun. But, I prefer to have more control over it in flight. I find being able to execute commands with keystrokes in emacs, the best way to do it. Here is a short video demonstrating control via the REPL. (Note: I am just doing simple take off / up and landings because of the constraints of flying indoors in my kitchen. There are many more moves you can do if you have more space.)\n(ns clj-drone.example.moves (:require [clj-drone.core :refer :all])) (drone-initialize) ;Use ip and port for non-standard drone ip/port ;(initialize ip port) (drone-do-for 4 :take-off) (drone-do-for 2 :up 0.3) (drone-do-for 3.75 :fly 0.2 0 0 0.5) ; sprial (drone :hover) (drone :land) Looking at the Navigation Data You can also hook into the navigation feed. There are many drone states and properties to look at. There is a list of all the ones currently available on the github project site. There are also many more, including targeting information, that have yet to be added. There is a logging function that will pair down the navigation properties that you are interested in. The navigation data map as an atom, so it can be de-referenced anywhere in your program. Here is a short video of what the navigation logging data looks like when it is turned on.\n(ns clj-drone.example.nav-test (:require [clj-drone.core :refer :all] [clj-drone.navdata :refer :all])) ;; logging is configured to go to the logs/drone.log file (set-log-data [:seq-num :flying :battery-percent :control-state :roll :pitch :yaw :velocity-x :velocity-y :velocity-z]) (drone-initialize) (drone-init-navdata) (drone :take-off) (drone :land) (end-navstream) Auto-piloting with goals and beliefs Inspired by reading John McCarthy\u0026rsquo;s paper on Ascribing Mental Qualities to Machines, the drone can also auto-pilot itself based on goals and beliefs about its streaming navigation data. You define belief-actions and then goals. Finally, you set a vector of the current goals for the drone to process. You can see an example here of the AR drone having three goals: Take off, Get to a cruising altitude, and then land. It does it solely by inspecting and acting on the streaming navigation data. Code for the program is here: https://github.com/gigasquid/clj-drone/blob/master/examples/nav_goals.clj\nGo Fly! I have had a lot of fun so far working on this project. I hope that you get a chance to play with it too. The project is still very young, so stay tuned for updates and, of course, pull requests are always welcome :)\n","permalink":"https://gigasquidsoftware.com/blog/2013/02/05/the-joy-of-flying-ar-drones-with-clojure/","summary":"\u003cp\u003eClojure is fun.  Flying \u003ca href=\"http://ardrone2.parrot.com/usa/\"\u003eAR Parrot Drones\u003c/a\u003e are fun.  Put them together and there is pure joy.\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/images/posts/4e9c7ed1-9925804126_e4707c8b72_o.jpg\"\u003e\u003c/p\u003e\n\u003cp\u003eEver since I found out that you could program and control your drone over UDP, I couldn\u0026rsquo;t wait to try it out in Clojure.  I had dreams of controlling it with my Emacs REPL.  That dream came true and it has been a true joy to fly in a function language. This blog post shows some of the features that the \u003ca href=\"https://github.com/gigasquid\"\u003eclj-drone project\u003c/a\u003e has so far.  There is still a bit of work to go to make it complete.  But, I wanted to share and hopefully encourage others to start playing with it too.\u003c/p\u003e","title":"The Joy of Flying AR Drones with Clojure"},{"content":"Saving the best for last. Elephant 2000\nTo be continued\u0026hellip;.\n","permalink":"https://gigasquidsoftware.com/blog/2013/01/02/7-mccarthy-papers-in-7ish-weeks-%237-elephant-2000/","summary":"\u003cp\u003eSaving the best for last.  \u003ca href=\"http://web.archive.org/web/20131014084908/http://www-formal.stanford.edu/jmc/elephant/elephant.html\"\u003eElephant 2000\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003eTo be continued\u0026hellip;.\u003c/p\u003e","title":"7 McCarthy Papers in 7ish weeks #7 - Elephant 2000"},{"content":"I spend most of my work day in Ruby and CoffeeScript. However, my true love belongs to Clojure, which I consider my \u0026ldquo;hobby\u0026rdquo; language right now. I started to wonder, what are the \u0026ldquo;hobby\u0026rdquo; languages for people who spend most of their work day with Clojure. My informal twitter poll revealed selection as diverse and interesting as the Clojurists themselves.\n**Developers Who Enjoy Clojure Also Enjoy: ** (In no particular order)\nGo (adorable mascot)\nOCaml\nFactor\nHaskell\nScala\nJulia\nMetaII\ncaerbannog\nJ\nBoo (.Net)\nJavaScript / Bash\nand of course MORE Clojure\nClojureScript\ncore.logic\nOvertone\nQuil\n","permalink":"https://gigasquidsoftware.com/blog/2012/12/26/hobby-languages-for-clojurists/","summary":"\u003cp\u003eI spend most of my work day in Ruby and CoffeeScript. However, my true love belongs to Clojure, which I consider my \u0026ldquo;hobby\u0026rdquo; language right now. I started to wonder, what are the \u0026ldquo;hobby\u0026rdquo; languages for people who spend most of their work day with Clojure. My informal twitter poll revealed selection as diverse and interesting as the Clojurists themselves.\u003c/p\u003e\n\u003cp\u003e**Developers Who Enjoy Clojure Also Enjoy: **\n\u003cem\u003e(In no particular order)\u003c/em\u003e\u003c/p\u003e","title":"Hobby Languages for Clojurists"},{"content":"\nThis holiday edition blog post covers two McCarthy papers instead of just one. We will be talking about Free Will - Even for Robots and the companion paper Simple Deterministic Free Will.\nIn which we deftly sidestep the philosophers We know that computers and programs are completely deterministic. A philosophical question is whether we, as humans are ruled by determinism, (although complex it may be), or not. If we take the decision that humans are deterministic, then we can argue that either there is no free will - or that free will is \u0026ldquo;compatible\u0026rdquo; with determinism. Philosophers, of course, could discuss such questions interminably, trying to get a theory to fit for all people and all occasions. Thankfully, McCarthy takes a very admirable and practical view on free will. Let\u0026rsquo;s try out something simple for a computer program and see how it works. He explores a philosophy \u0026ldquo;Compatibilist\u0026rsquo;s\u0026rdquo; view, which regards a person to have free will if his actions are decided by an internal process, even if this process itself is deterministic. But by exploring this view with computer programs, he makes clear:\n\u0026hellip; I don\u0026rsquo;t need to take a position on determinism itself.\nSimple Deterministic Free Will So what would Free Will look like for a machine. How do we go about defining it? McCarthy proposes the idea of Simple Deterministic Free Will. The main idea is that the mechanism of free will is broken up into two parts. The first part looks at the possible actions and the consequences of those actions, and the second part decides which of those actions are preferable and does them. He gives the example of a chess program:\nPeople and chess programs carry thinking about choice beyond the ﬁrst level. Thus “If I make this move, my opponent (or nature regarded as an opponent) will have the following choices, each of which will give me further choices.” Examining such trees of possibilities is an aspect of free will in the world, but the simplest form of free will in a deterministic world does not involve branching more than once.\nSo perhaps we could find an example that is simpler than chess to work with \u0026hellip;\n\u0026hellip;it would be interesting to design the simplest possible system exhibiting deterministic free will. A program for tic-tac-toe is simpler than a chess program, but the usual program does consider choices.\nSimple Deterministic Free Will Tic Tac Toe So to explore McCarthy\u0026rsquo;s idea of Simple Deterministic Free Will, I decided to try to construct a game of Tic Tac Toe with SDFW principles. Coincidentally, my six year old daughter, just learned how to play Tic Tac Toe as well. I wanted to construct a program that would \u0026ldquo;reason\u0026rdquo; about the game as would a child. Even though the game of Tic Tac Toe is simple enough to have all the possibility trees of moves completely solved, this is not how a my daughter approaches the game. Each time it is her move, she only looks one move ahead to see if she can win three in a row, or if she needs to block her opponent from winning the next move.\nMy Tic Tac Toe Program has Beliefs It has three beliefs to be precise. It believes that no one is going to win, or it is going to win, or its opponent is going to win.\n(def beliefs { :win \u0026quot;I am going to win.\u0026quot; :lose \u0026quot;My opponent is going to win.\u0026quot; :noone \u0026quot;No one is going to win.\u0026quot;}) McCarthy thinks that ascribing programs beliefs can be useful. One of the reasons is that it helps us as humans, reason and debug our programs. I definitely saw the value of this when I was trying to debug my tic tac toe game. After it failed to block my winning move, I could see what its false belief was - ah - it thought that \u0026ldquo;No one is going to win\u0026rdquo;. I wrote another failing unit test to fix its bad belief.\nMy Tic Tac Toe Program Looks to See What Its Possible Actions and Preferences Are It looks at the board and computes all its possible next moves. Then it computes all the possible next moves of its opponent. It looks at the consequences of these moves by assigning a belief from one of its three beliefs. Next, it ranks the moves according to the preference of its beliefs.\n(def belief-action-preferences { (beliefs :win) 1 (beliefs :lose) 2 (beliefs :noone) 3}) It then chooses the move to take that has the highest rank. If it believes that no-one is going to win, I opted to have it choose a random move from the list of possible choices. But this randomness is completely arbitrary on my part and not necessary to SDFW at all.\nWhy ClojureScript is Awesome I coded the core tic-tac-toe program in Clojure, but then I thought that having a web page UI would be nice for my daughter to play with. So, I just took the game logic and moved it to ClojureScript. Let me say that again slower\u0026hellip; I used the same code on the server on the browser. Awesome. Using the lein-cljsbuild crossover support, I was able to simply configure my UI ClojureScript code to access my regular clojure game engine. Very cool. I was also very pleased to work with the https://github.com/levand/domina DOM manipulation library for ClojureScript.\nEnd Result It was a fun project that let me play with ClojureScript, explore McCarthy\u0026rsquo;s free will for robots, have some very interesting conversations about free will with my co-wokers and code and coffee friends, and make a game for my daughter to play and enjoy. If you are interested in checking out the program for yourself - http://gigasquid.github.com/sdfw-tic-tac-toe/. The last belief is displayed at the bottom. I have only tried it on Chrome, so beware. Finally, if you find any false beliefs, feel free to submit a pull request to https://github.com/gigasquid/sdfw-tic-tac-toe.\nP.S. If you are wondering, I drew the awesome graphics all by myself.\n","permalink":"https://gigasquidsoftware.com/blog/2012/11/25/7-mccarthy-papers-in-7ish-weeks-%235-%236-sdfw-tic-tac-toe/","summary":"\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/images/posts/6135b784-9925780935_9744792c36_o.png\"\u003e\u003c/p\u003e\n\u003cp\u003eThis holiday edition blog post covers two McCarthy papers instead of just one.  We will be talking about \u003ca href=\"http://web.archive.org/web/20131014084908/http://www-formal.stanford.edu/jmc/freewill.pdf\"\u003eFree Will - Even for Robots\u003c/a\u003e and the companion paper \u003ca href=\"http://web.archive.org/web/20131014084908/http://www-formal.stanford.edu/jmc/freewill2.pdf\"\u003eSimple Deterministic Free Will\u003c/a\u003e.\u003c/p\u003e\n\u003ch2 id=\"in-which-we-deftly-sidestep-the-philosophers\"\u003eIn which we deftly sidestep the philosophers\u003c/h2\u003e\n\u003cp\u003eWe know that computers and programs are completely deterministic.  A philosophical question is whether we, as humans are ruled by determinism, (although complex it may be), or not.  If we take the decision that humans are deterministic, then we can argue that either there is no free will - or that free will is \u0026ldquo;compatible\u0026rdquo; with determinism.  Philosophers, of course, could discuss such questions interminably, trying to get a theory to fit for all people and all occasions.  Thankfully, McCarthy takes a very admirable and practical view on free will.  Let\u0026rsquo;s try out something simple for a computer program and see how it works.  He explores a philosophy \u0026ldquo;Compatibilist\u0026rsquo;s\u0026rdquo; view, which regards a person to have free will if his actions are decided by an internal process, even if this process itself is deterministic.  But by exploring this view with computer programs, he makes clear:\u003c/p\u003e","title":"7 McCarthy Papers in 7ish Weeks #5 \u0026 #6 - SDFW Tic-Tac-Toe"},{"content":"Reading Artificial Intelligence, Logic, and Formalizing Common Sense, led me surprisingly to reflect on, not only logic and philosophy, but also the history and present state of AI.\nFist let\u0026rsquo;s look at the kind of AI that McCarthy is describing in paper. He talks of a program that can use common sense knowledge about the world around it and have this knowledge structured well enough that it can be reasoned about mathematically. In fact, he describes four levels of logic:\nThe computer program has its \u0026ldquo;beliefs\u0026rdquo; completely defined by its internal state. If you are confused by the term \u0026ldquo;beliefs\u0026rdquo;, it refers to ascribing mental qualities to machines. In his famous example, a thermostat has three beliefs: the room is too hot, the room is too cold, and the room is just right.\nThe programs express their beliefs in sentences in machine memory. However, they do not use ordinary logic. They use other methods like rules and procedures.\nIn addition to expresses their beliefs in sentences, they also use first order logic and logical deduction to reach their conclusions.\nThe fourth level is still a goal today. It is to have the program represent general facts about the world as logical sentences. Furthermore, to have a database of these commonsense facts that programs can share.\nLet\u0026rsquo;s step back now for a moment, to a excerpt from the very beginning of the paper:\nOne path to human-level AI uses mathematical logic to formalize common-sense knowledge in such a way that common-sense problems can be solved by logical reasoning. This methodology requires understanding the common-sense world well enough to formalize facts about it and ways of achieving goals in it. Basing AI on understanding the common-sense world is different from basing it on understanding human psychology or neurophysiology.\nThis approach to AI is just one approach. It is commonly referred to as a \u0026ldquo;top down\u0026rdquo; approach. In the early years of AI it was the dominant way of thinking about things. Looking back at the history of AI, the golden years were full of optimism, (and funding), that this was the path to achieving fully intelligent machines. Disenchantment with unfulfilled promises, led to the first AI winter. There was a rise of expert systems later on that limited their scope to small domains and avoided the common sense problem, but eventually ended in a second AI winter and ushered in our current world. This basic approach is an opposite ground-up view of AI. It uses neural networks and statistics from a physical inspiration. Some of this inspiration is from human neurophysiology, some of it is from insect and animal world, but simplicity behavior of a \u0026ldquo;body\u0026rdquo; is emphasized. With the advances in hardware and computing power today, the innovations and accomplishments have been breath taking.\nA good example of the two approaches can be seen in my Roomba. A top down approach, would require my Roomba to have a complete room model in its program. It would have to understand what my couch was, where the doors where and have logically reasoning to direct it to which areas to clean and when to stop cleaning and recharge itself. The creators of the Roomba were from the opposite camp of thinking. They took the simpler behavior approach of having the Roomba just take a random walk in the room and turn around when it ran into an obstacle. It took a bit longer to get the room clean in such a random fashion, but not having to deal with the overhead of a mental model was well worth the trade off.\nNoam Chomsky recently argued that the pendulum has swung too far in favor of this simplified behaviorist approach. Even in the light of Norvig\u0026rsquo;s response, I think Chomsky has a point. We would do well to search for gems of true intelligent systems in the historical landscape of the AI Winter. Some of the breakthroughs of current sheer computing power and new modeling techniques, might yield great fruits.\nOne of the comments by nagelonce, on the Chomsky article, puts this very well:\nAI has a hole in the middle. There\u0026rsquo;s top-down AI, which focuses on abstractions and reductionism. There\u0026rsquo;s bottom-up AI, which focuses on reactive systems and the front end of visual processing. They have yet to meet in the middle. They are, however, much closer to doing so than they were twenty years ago.\nIf you are interested in checking out a top-down open source AI project, take a look at OpenCyc. After a brief look at it the other night, it suffers from the lack of love and documentation. But, I can also see the promise of McCarthy\u0026rsquo;s common sense knowledge and logic system, covered in a thin layer of snow.\n","permalink":"https://gigasquidsoftware.com/blog/2012/11/06/7-mccarthy-papers-in-7ish-weeks-%234/","summary":"\u003cp\u003eReading \u003ca href=\"http://www-formal.stanford.edu/jmc/ailogic/ailogic.html\"\u003eArtificial Intelligence, Logic, and Formalizing Common Sense\u003c/a\u003e, led me surprisingly to reflect on, not only logic and philosophy, but also the history and present state of AI.\u003c/p\u003e\n\u003cp\u003eFist let\u0026rsquo;s look at the kind of AI that McCarthy is describing in paper. He talks of a program that can use common sense knowledge about the world around it and have this knowledge structured well enough that it can be reasoned about mathematically. In fact, he describes four levels of logic:\u003c/p\u003e","title":"7 McCarthy Papers in 7ish Weeks - #4"},{"content":"In which I realize that John McCarthy is the father of the Semantic Web\nI have realized that it generally takes me more than a week to read a paper, reflect on it, experiment, and finally blog about it. But, since I made up the rules of the project in the first place, I am not going to dwell on the time frame and just move forward with the next paper.\nWhen I picked the paper First Order Theories of Individual Concepts and Propositions, I thought to myself that it would be a rather narrow, more self contained paper than the first two broad papers that I read. However, the connections that it drew to current technologies caught me by surprise.\nThe main point of the paper is how to formalize language statements, including concepts, so that a computer can apply mathematical rules and logic to them. McCarthy had mentioned concepts and thoughts in his \u0026ldquo;Ascribing Mental Qualities\u0026rdquo; paper, where he says:\n\u0026ldquo;..the deep structure\u0026rdquo; of a publicly expressible thought is a node is the public network.\u0026quot;\nThis immediately brought to my mind the Semantic Web. In Semantic Web, data is structured in RDF statements as triples - . The data contained in these triples are structured and described so that machines can derive context and meaning from it. For example, instead of just putting \u0026ldquo;cat\u0026rdquo; as the subject. In RDF you would use http://dbpedia.org/resource/Cat as the subject. Which, is pretty much dead on McCarthy\u0026rsquo;s expressible thought as a node in the public network.\nMcCarthy uses the following example to illustrate how to construct First Order statements.\nFrege (1892) discussed the need to distinguish direct and indirect use of words. According to one interpretation of Frege\u0026rsquo;s ideas, the meaning of the phrase \u0026ldquo;Mike\u0026rsquo;s telephone number\u0026rdquo; in the sentence \u0026ldquo;Pat knows Mike\u0026rsquo;s telephone number\u0026rdquo; is the concept of Mike\u0026rsquo;s telephone number, whereas its meaning in the sentence \u0026ldquo;Pat dialed Mike\u0026rsquo;s telephone number\u0026rdquo; is the number itself. Thus if we also have Mary\u0026rsquo;s telephone number = Mike\u0026rsquo;s telephone number\u0026quot;, then Pat dialed Mary\u0026rsquo;s telephone number\u0026quot; follows, but \u0026ldquo;Pat knows Mary\u0026rsquo;s telephone number does not. phone number\u0026rdquo; is the number itself. Thus if we also have Mary\u0026rsquo;s telephone number = Mike\u0026rsquo;s telephone number\u0026quot;, then Pat dialed Mary\u0026rsquo;s telephone number\u0026quot; follows, but Pat knows Mary\u0026rsquo;s telephone number does not.\nMcCarthy express the statement \u0026ldquo;Pat knows Mike\u0026rsquo;s telephone number\u0026rdquo; as:\ntrue Know(Pat; Telephone Mike)\nHe then uses more formalized statements to derive logic statements and reasoning from this example.\nAt this point, I was seeing more connections to the field of Semantic Web. Expressing data in RDF/ OWL gives computers exactly this type of logic and reasoning ability too.\nSo how would you go about expressing \u0026ldquo;Pat knows Mike\u0026rsquo;s telephone number\u0026rdquo; in Semantic Web data form? This question is not a simple one,(at least for me), because there are so many different ways that you can construct RDF. The choices were a bit overwhelming.\nOne option might be to use RDF reification, in which you can make statements about statements. Another option might be using OWL classes and properties. There are some excellent answers when I posed the question on http://stackoverflow.com/questions/13114018/how-to-state-pat-knows-mikes-telephone-number-in-rdf-owl.\nIndeed, it seems that we can express individual concepts and propositions in Semantic Web form quite well. I had not realized that John McCarthy is the father of Sematic Web as well.\nIn closing, he speaks of AI Applications. Reasoning and predication are familiar applications that we use today. However he hits upon one that is quite interesting to me. That is \u0026ldquo;..determining that it **does not know **something or that someone else doesn\u0026rsquo;t.\u0026rdquo; This is not a common area to think about with computer programs. We are usually much more focused on what it does know and how to reason about it. But, if we are really to build intelligent, learning systems, we need to be able to identify what it does not know as well. Perhaps then the AI can help us humans, who are pretty bad at that too.\n","permalink":"https://gigasquidsoftware.com/blog/2012/10/15/7-john-mccarthy-papers-in-7-weeks-%233/","summary":"\u003cp\u003e\u003cstrong\u003eIn which I realize that John McCarthy is the father of the Semantic Web\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003eI have realized that it generally takes me more than a week to read a paper, reflect on it, experiment, and finally blog about it. But, since I made up the rules of the project in the first place,  I am not going to dwell on the time frame and just move forward with the next paper.\u003c/p\u003e","title":"7 John McCarthy Papers in 7 Weeks #3"},{"content":"Well, life threw me for a bit of a loop and delayed my post on my second paper. So I am going to consider this a \u0026ldquo;weekish\u0026rdquo; period of time and just continue on.\nI read Towards a Mathematical Science of Computation. It is quite a meaty paper and was certainly a lot to digest. Here are some highlights that I gleaned from it.\nHow can a Mathematical Science of Computation help in a practical way? McCarthy points out that while it is hard to predict practical applications ahead of time. A couple of could be\nProvide a systematic way to create of programming language. Rather than just arguing and arbitrarily adding language features whilly nilly.\n\u0026ldquo;It should be possible to eliminate debugging. Debugging is the testing of a program on cases one hopes are typical, until it seems to work. This frequently is in vain.\u0026rdquo;\nThis last point of being able to eliminate debugging really stuck with me. Even with the best of TDD and test suites, we as developers still struggle with the testing of programs against what we hope is \u0026ldquo;typical\u0026rdquo;. Over the past years we have improved our techniques and made our programs more robust, but it would certainly be nice to be able to prove a program correct.\nIf fear that even if this was possible, it would not be enough. At least in my experience, a considerable amount of debugging happens at the human level:\nThe translation of understanding of what the human product owner wants to what the software developer can understand.\nThe human product owner\u0026rsquo;s understanding of what they want in the first place.\nIn my experience, we have just as much trouble (or even more) stating the problem for the program as we do in attempting to solve and prove that it works.\nWhat we already know that can be applied to a Mathematical Science of Computation The existence of Turing\u0026rsquo;s Universal computers\nThe existence of classes of unsolvable problems\nPerhaps a sonic screwdriver will help? McCarthy then goes on to add another tool to the Mathematical Science of computation toolbox. He shows that conditional expressions can be defined recursively. Then he expands this to relate to programs/computers that can be defined recursively.\nCan a man make a computer program that is as intelligent as him? Here is the real question. McCarthy has us consider the following problem of whether a program on a computers with unlimited memory will ever stop:\nA procedure does the following\nIf the number is in a creative set then return -\u0026gt; yes. If a number is not in a creative set then return -\u0026gt; no or it may run indefinitely\nThere is no procedure while will always return -\u0026gt; yes when the answer is yes. and return -\u0026gt; no when the answer is no\nIt is a bit depressing that we can\u0026rsquo;t figure out which ones that are really no and which ones run forever. But don\u0026rsquo;t give up. We can just try to do the best we can. Emil Post discovered that whenever we try to do the best we can, one can always improve upon it. He showed that given any procedure, he could make a new procedure that solved all the previous cases plus some new ones. McCarthy pointed out that this process, even though it is really like trying to count the biggest ordinal number, can be mechanized. So really there is no reason why a machine could not continually improve its own program.\nIn summary, McCarthy\u0026rsquo;s own words are the best:\n\u0026ldquo;In conclusion, let me re-assert that the question of whether there are limitations in principle of what problems man can make machines solve for him as compared to his own ability to solve problems, really is a technical question in recursive function theory.\u0026rdquo;\n","permalink":"https://gigasquidsoftware.com/blog/2012/09/29/7-john-mccarthy-papers-in-7-weeks-%232/","summary":"\u003cp\u003eWell, life threw me for a bit of a loop and delayed my post on my second paper. So I am going to consider this a \u0026ldquo;weekish\u0026rdquo; period of time and just continue on.\u003c/p\u003e\n\u003cp\u003eI read \u003ca href=\"http://web.archive.org/web/20131014084908/http://www-formal.stanford.edu/jmc/towards/towards.html\"\u003e Towards a Mathematical Science of Computation\u003c/a\u003e.  It is quite a meaty paper and was certainly a lot to digest.  Here are some highlights that I gleaned from it.\u003c/p\u003e\n\u003ch3 id=\"how-can-a-mathematical-science-of-computation-help-in-a-practical-way\"\u003eHow can a Mathematical Science of Computation help in a practical way?\u003c/h3\u003e\n\u003cp\u003eMcCarthy points out that while it is hard to predict practical applications ahead of time.  A couple of could be\u003c/p\u003e","title":"7 John McCarthy Papers in 7 Weeks - #2"},{"content":"\nAscribing Mental Qualities to Machines or How My Thermostat has Beliefs and Goals After reading John McCarthy\u0026rsquo;s paper this week Ascribing Mental Qualities to Machines, I can honestly say that it has changed the way I think about programs and most certainly thermostats. For you see, I realize now that my thermostat has beliefs and goals. No, it does not have beliefs about what the weather is going to be tomorrow, or when the next George R.R. Martin book is going to come out. But it does have beliefs. It has three of them to be exact:\nThe room is too hot\nThe room is too cold\nThe room is OK\nIt also only has one goal:\nThe room should be OK Wat? Why should we think of a simple thermostat this way? It is not very complex. In fact, we can completely understand its state and reason about its behavior by looking at its small and complete program listing. What benefit can there possibly be to endow the humble thermostat with its own beliefs and goals?\nStart Small Let\u0026rsquo;s step back. We are talking about designing and building intelligent systems, not just programs. The example of a thermostat is indeed small, but let us try out our ideas on a easy to understand system first. Later we can consider applying it to more complex systems.\nBeliefs and Goals are Easier to Understand and Reason About Using a higher level construct to express state can make it easier to reason and understand intelligent systems. It also is useful in describing states that are not completely known or have portions that are not easily observable. In short, defining a program\u0026rsquo;s state in terms of beliefs and goals may be closer to our natural way of thinking. When I consider my co-worker sitting next to me. I cannot hope to observe the complete mental state of him at that moment. Although I could hope to describe it at a high level with beliefs and goals. I could even hope to predict future behavior with this knowledge of his beliefs and goals, (which most likely has to do with the goal of eating more bacon).\nEasier to Debug and Correct Once we have a higher level model of a systems mental state and behavior. It would be easier to debug, communicate, and correct problems. For example, If I come home and the room is way too cold, I could look for the problem in terms of beliefs and goals. Does the thermostat have a faulty belief? Or did it have a good belief that the room was too cold? If so, then the problem was that it could not act on its belief to tell the furnace to turn on. If it could communicate and know the problem, perhaps it could message me and I could arrange a service call, or it could even self-correct. Another example, is my recent experience with my Roomba. I came home the other day to find my Roomba had not returned to its charging station after its scheduled cleaning. Instead, it was stopped under my bed. What went wrong? Did it believe that the battery was low? Or was there some other faulty belief? It would be nice if it could tell me.\nDelving Further - What is a belief? McCarthy talks about defining a belief as a function of the system\u0026rsquo;s state. For each state, there are beliefs that can be expressed as a sentences in a language. The machine does not need to understand the meaning and concepts in the English, French or any given language. That is for us to interpret. The important part is that there is a mapping of the state to this sentence. Taking our humble thermostat for an example:\n(defn thermo-belief [temp] (cond (\u0026gt; temp 70) \u0026quot;The room is too hot.\u0026quot; (\u0026lt; temp 70) \u0026quot;The room is too cold.\u0026quot; :else \u0026quot;The room is OK.\u0026quot;)) We can test our thermostats beliefs with something like:\n(deftest thermo-beliefs-tests (is (= \u0026quot;The room is too hot.\u0026quot; (thermo-belief 71))) (is (= \u0026quot;The room is too cold.\u0026quot; (thermo-belief 69))) (is (= \u0026quot;The room is OK.\u0026quot; (thermo-belief 70)))) This testing or criticizing the belief structure of the thermostat is what McCarthy called a Second Order Structural definition for mental qualities. This differs from a First Order Structural definition in that, rather than criticizing or testing an individual belief, he sought to describe them by testing/ criticizing the structure of the whole set of beliefs.\nIn the example of our thermostat, to have a \u0026ldquo;good\u0026rdquo; belief structure, in accordance with Second Order Structural definition, it the must have some consequences or actions of it beliefs. Furthermore, these actions most be consistent with its goals.\nIt might be expressed in code like this:\n(defn thermo-action [belief temp] (case belief \u0026quot;The room is too hot.\u0026quot; (dec temp) \u0026quot;The room is too cold.\u0026quot; (inc temp) \u0026quot;The room is ok.\u0026quot; temp)) In this case, the action of a belief is returning a new state, the temperature. Our thermostat could issue a command to the furnace to turn on. But, let us keep it simple for the moment and just think of its action directly changing the temperature. Now, our believing thermostat program can be described as having beliefs as well as taking actions from them.\n(defn thermostat [temp] (thermo-action (thermo-belief temp) temp)) (thermostat 33) ;=\u0026gt; 34 So now we have a thermostat that has beliefs and consequences from these beliefs. We still need to figure out how to test that its belief system is consistent with its goals. Thankfully, it only has one goal to keep it simple. The goal is that the room should be OK.\n(def goal 70) Let\u0026rsquo;s say that the thermostat is doing what it believes will achieve its goals, if the new temperature is closer to its goal.\n(defn distance-from-goal [g t] (Math/abs (- g t))) (distance-from-goal goal 80) ;=\u0026gt; 10 (defn closer-to-goal [g t nt] (\u0026gt; (distance-from-goal g t) (distance-from-goal g nt))) (closer-to-goal goal 75 73) ;=\u0026gt; true (closer-to-goal goal 75 76) ;=\u0026gt; false (closer-to-goal goal 56 57) ;=\u0026gt; true We can now construct a test to see if the thermostat actions are consistent with its goals.\n(deftest themo-behavior-test (is (closer-to-goal goal 4 (thermostat 4))) (is (closer-to-goal goal 74 (thermostat 74))) (is (closer-to-goal goal 75 (thermostat 75))) (is (closer-to-goal goal 56 (thermostat 56)))) Given this particular thermostat example, we could even recursively show that it will reach its goal:\n(defn thermo-simulation [g s] (if (= g s) \u0026quot;Woo hoo!\u0026quot; (thermo-simulation g (thermostat s)))) (thermo-simulation goal 73) ;=\u0026gt;; \u0026quot;Woo hoo!\u0026quot; (deftest thermo-goal-achievement-test (is (= \u0026quot;Woo hoo!\u0026quot; (thermo-simulation goal 73))) (is (= \u0026quot;Woo hoo!\u0026quot; (thermo-simulation goal 100))) (is (= \u0026quot;Woo hoo!\u0026quot; (thermo-simulation goal 33))) (is (= \u0026quot;Woo hoo!\u0026quot; (thermo-simulation goal -33))) ) Our thermostat\u0026rsquo;s beliefs are good!\nWhat if \u0026hellip;. The way that McCarthy explains the Second Order Structural definition as criticizing and testing beliefs, made me start thinking about test driven design. What if we were to start thinking and designing our programs with this testing of belief and goal structure? It could be IDD (Intelligence Driven Design) rather than TDD/ BDD. From experience, I know that TDD has changed the way that I think about coding and resulted in cleaner and more robust programs. I wonder what effect IDD could have on our program\u0026rsquo;s creation and perhaps the future of AI. Could changing the way we approach our definition of state and behavior change our software to become more intelligent? Wait a minute. If we write a test system to criticize another programs beliefs and goals, wouldn\u0026rsquo;t we be designing a program that would have beliefs about another program\u0026rsquo;s beliefs?\n\u0026hellip;\n\u0026hellip;\nMy brain get exploded. It is in fact, turtles all the way down :)\n","permalink":"https://gigasquidsoftware.com/blog/2012/09/20/7-john-mccarthy-papers-in-7-weeks-%231-how-my-thermostat-has-beliefs-and-goals/","summary":"\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/images/posts/6f1191f2-447335691_8a933251ab_n.jpg\"\u003e\u003c/p\u003e\n\u003ch2 id=\"ascribing-mental-qualities-to-machines-or-how-my-thermostat-has-beliefs-and-goals\"\u003eAscribing Mental Qualities to Machines or How My Thermostat has Beliefs and Goals\u003c/h2\u003e\n\u003cp\u003eAfter reading John McCarthy\u0026rsquo;s paper this week \u003ca href=\"http://web.archive.org/web/20131014084908/http://www-formal.stanford.edu/jmc/\"\u003eAscribing Mental Qualities to Machines\u003c/a\u003e, I can honestly say that it has changed the way I think about programs and most certainly thermostats. For you see, I realize now that my thermostat has beliefs and goals. No, it does not have beliefs about what the weather is going to be tomorrow, or when the next George R.R. Martin book is going to come out. But it does have beliefs. It has three of them to be exact:\u003c/p\u003e","title":"7 John McCarthy Papers in 7 weeks – #1 How My Thermostat has Beliefs and Goals"},{"content":"In the spirit of Seven Languages in Seven Weeks, I have decided to embark on a quest. But instead of focusing on expanding my mindset with different programming languages, I am focusing on trying to get into the mindset of John McCarthy, father of LISP and AI, by reading and thinking about seven of his papers.\nWhy? Get out of your box If you are comfortable, you are not challenging yourself to grow. You are doomed to stay in your same mindset and your little box and your world gets smaller. As an Object Oriented programmer, I was happy in my little box. Then one day, I discovered Clojure and Functional Programming and my world became bigger and richer because of it. I hope to glean a similar box expansion, by exploring the thoughts of McCarthy. Especially, since I have the nagging suspicion that we are somehow doing programming \u0026ldquo;completely wrong.\u0026rdquo;\nSlow Down Reading papers is an antidote to today\u0026rsquo;s relentless stream of Twitter and Hacker News techno stuff. It forces you to slow down and read something \u0026hellip;gasp, maybe even the same thing multiple times and digest it. Thinking slow and eating more veggies is something we could all do more.\nStructure Following a somewhat arbitrary schedule of seven papers in seven weeks gives a structure that gives an measurable goal and timeline to this endeavor. Which gives you a fighting chance of actually getting it accomplished.\nThe Answer is Never Too Far Away When we are presented with a problem, more often then not, the answer comes to us from some of our recent thoughts and experiences. Many breakthroughs in new technologies have come from cross pollination across different fields. Exposing yourself to a new ways of thinking gives your creative problem solving abilities new and powerful ammunition.\nEncourage Others Serendipity moves in mysterious ways. By sharing your travels and thoughts, who knows what might spark in someone else\u0026rsquo;s mind\u0026hellip;\nSo I encourage you to join along. Pick a paper that appeals to you and read it this week. Think about it, talk to your co-workers about it, maybe write about it, or even code from it. But most importantly, slow down and take a moment to peek outside your box.\n","permalink":"https://gigasquidsoftware.com/blog/2012/09/19/7-john-mccarthy-papers-in-7-weeks-prologue/","summary":"\u003cp\u003eIn the spirit of \u003ca href=\"http://pragprog.com/book/btlang/seven-languages-in-seven-weeks\"\u003eSeven Languages in Seven Weeks\u003c/a\u003e, I have decided to embark on a quest. But instead of focusing on expanding my mindset with different programming languages, I am focusing on trying to get into the mindset of \u003ca href=\"http://en.wikipedia.org/wiki/John_McCarthy_(computer_scientist)\"\u003eJohn McCarthy\u003c/a\u003e, father of LISP and AI, by reading and thinking about seven of his \u003ca href=\"http://web.archive.org/web/20131014084908/http://www-formal.stanford.edu/jmc/\"\u003epapers\u003c/a\u003e.\u003c/p\u003e\n\u003ch3 id=\"why\"\u003eWhy?\u003c/h3\u003e\n\u003ch4 id=\"get-out-of-your-box\"\u003eGet out of your box\u003c/h4\u003e\n\u003cp\u003eIf you are comfortable, you are not challenging yourself to grow.  You are doomed to stay in your same mindset and your little box and your world gets smaller.  As an Object Oriented programmer, I was happy in my little box.  Then one day, I discovered Clojure and Functional Programming and my world became bigger and richer because of it.  I hope to glean a similar box expansion, by exploring the thoughts of McCarthy.  Especially, since I have the nagging suspicion that we are somehow doing programming \u003ca href=\"http://www.catonmat.net/blog/wp-content/uploads/2008/12/john-mccarthy-programming-wrong.jpg\"\u003e\u0026ldquo;completely wrong.\u0026rdquo;\u003c/a\u003e\u003c/p\u003e","title":"7 John McCarthy Papers in 7 weeks - Prologue"},{"content":" One of the things that I love about Clojure is that it can go anywhere that Java can. That is why, when I found out that the Roomba already had a Java library written for it - I was excited to be able to hook it up to my Emacs / Swank and be able to control it from my editor.\nIt is great fun! If you have a Roomba at home and you want to play along\u0026hellip;\nRead [Setting up and Configuring Bluetooth and Roomba part from this post](http://gigasquidsoftware.com/blog/2012/08/02/talking-to-your-roomba-via-bluetooth-and-roombacom/). Checkout the sample project clj-roomba from github. Have fun doing this like this:\n(def roomba (RoombaCommSerial. )) ;;Find your port for your Roomba (map println (.listPorts roomba)) (def portname \u0026quot;/dev/cu.FireFly-943A-SPP\u0026quot;) (.connect roomba portname) (.startup roomba) ;;puts Roomba in safe Mode ;; What mode is Roomba in? (.modeAsString roomba) (.control roomba) (.updateSensors roomba) ; returns true if you are connected (.pause roomba 30) (.playNote roomba 72 40) (.playNote roomba 79 40) (.spinLeft roomba) (.spinRight roomba) (.goBackward roomba) (.goForward roomba) (.turnLeft roomba) (.turnRight roomba) (.stop roomba) (.reset roomba) (.vacuum roomba true) (.vacuum roomba false) (.clean roomba) ;; Get the sensor data (.updateSensors roomba) (.bumpLeft roomba) (.bumpRight roomba) (.wheelDropLeft roomba) (.wheelDropRight roomba) (.wheelDropCenter roomba) (.sensorsAsString roomba) (defn bark [r] (doto r (.vacuum true) (.playNote 50 5) (.pause 150) (.vacuum false))) (bark roomba) A quick video of hacking Roomba in action\nNext up - Getting more roombas to implement Rich Hickey\u0026rsquo;s ant colony demo\u0026hellip;\n","permalink":"https://gigasquidsoftware.com/blog/2012/08/09/a-clojure-repl-driven-roomba/","summary":"\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/images/posts/96653a55-9925780955_4a32b8dc8a_o.jpg\"\u003e\nOne of the things that I love about Clojure is that it can go anywhere that Java can.  That is why, when I found out that the Roomba already had a \u003ca href=\"http://hackingroomba.com/code/roombacomm/\"\u003eJava library\u003c/a\u003e written for it - I was excited to be able to hook it up to my Emacs / Swank and be able to control it from my editor.\u003c/p\u003e\n\u003cp\u003eIt is great fun!  If you have a Roomba at home and you want to play along\u0026hellip;\u003c/p\u003e","title":"A Clojure REPL Driven Roomba"},{"content":"I love Roomba. It cleans our floors and it can be hacked to help teach my kids programming. Win!\nHere are the setup steps that I used to get going talking to Roomba:\nOrdered a Rootooth bluetooth connection for Roomba. I could have build one from scratch, but I am a busy mom and hacker.\nRemoved the cover from Roomba to expose the ROI port (Video).\nSetup the Bluetooth adapter on my Mac\nStart Bluetooth network assistant\nHave the firefly adapter deteted\nEnter the passkey: 1234\nClick edit serial ports to see what port it assigned. Mine was FireFly-943A-SPP. Alternatively, you can look at /dev directory\nNext, you need to configure the baud rate for your Roomba. I found these instructions helpful\nInstall zterm on your mac - set the serial port to your roomba and the baud rate to the correct baud rate\nOn zterm you now should be able to echo any key you type\nDownload RoombaComm java package\nLook at the README. You will need to run makeit.sh to build and ./rxtxlib/macosx_setup.command (for Macs)\nFinally run RoombaCommTest.sh to connect up and control your Roomba!\n","permalink":"https://gigasquidsoftware.com/blog/2012/08/02/talking-to-your-roomba-via-bluetooth-and-roombacomm/","summary":"\u003cp\u003eI love Roomba. It cleans our floors and it can be \u003ca href=\"http://www.irobot.com/images/consumer/hacker/roomba_sci_spec_manual.pdf\"\u003ehacked\u003c/a\u003e to help teach my kids programming. Win!\u003c/p\u003e\n\u003cp\u003eHere are the setup steps that I used to get going talking to Roomba:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003eOrdered a \u003ca href=\"https://www.sparkfun.com/products/10980?\"\u003eRootooth\u003c/a\u003e bluetooth connection for Roomba.  I could have build one from \u003ca href=\"http://hackingroomba.com/projects/build-a-roomba-bluetooth-adapter/\"\u003escratch\u003c/a\u003e, but I am a busy mom and hacker.\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eRemoved the cover from Roomba to expose the ROI port (\u003ca href=\"http://www.youtube.com/watch?v=EaZibdOIeD0\"\u003eVideo\u003c/a\u003e).\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eSetup the Bluetooth adapter on my Mac\u003c/p\u003e","title":"Talking to your Roomba via Bluetooth and RoombaComm"},{"content":"\nOnce upon a time, a young girl decided to take a break from her code and stroll in the forest. It was quite a pleasant day, she packed her lunch in her bag and set off. While she was walking, she started thinking about a concurrency bug that her OO project was having. As she pondered the complexities of mutablilty, state, and threads, she must of strayed from the trail and lost track of time. By the time she looked around, she realized that she was totally lost.\nIt was then she spotted a very strange hut on chicken legs in the middle of the forest. The door was open, and there was a ladder leading up to it. She yelled \u0026ldquo;Hello\u0026rdquo;, but there was no response. She climbed up the ladder and entered the hut to see if she could find anyone inside. The hut was empty except for a pile of old books, a large kettle, and very skinny, malnourished black cat. Her heart went out to the poor cat. She took her sandwich from her bag and watched as the cat greedily ate it. The cat looked up at her and said, \u0026ldquo;Thank you for your kindness. Now, you should really get out of her before Baba Yaga \u0026hellip;\u0026rdquo;\nA large gust of wind came at the door and Baba Yaga appeared. She smiled an iron tooth grin at the girl and said, \u0026ldquo;What do we have here? An intruder!\u0026rdquo;.\nThe girl stammered out, \u0026ldquo;I am sorry, it is just a mistake. I am lost ..\u0026rdquo;\n\u0026ldquo;Too late!\u0026rdquo; Baba Yaga grinned larger. \u0026ldquo;You are now my slave and if you don\u0026rsquo;t complete my tasks, I will eat you for my supper.\u0026rdquo; She thought for a moment and then pulled a book titled The Odyssey from the pile. \u0026ldquo;Your first task is to calculate the hash code of every character this book. Then sum of the values of only the even ones. Make sure you have it done before I return. And do it fast, I will be timing you.\u0026rdquo; Baba Yaga turned and disappeared in a gust of wind, with the door slamming and locking firmly in place behind her.\nThe girl sunk to the floor and started to weep. How could she complete the task? The cat rubbed up against her and purred, \u0026ldquo;You showed kindess to me where Baba Yaga never has. I will help you. It seems like this task would be best suited to a Clojure map, filter, and reduce, don\u0026rsquo;t you think?\u0026rdquo;\nThe girl wiped her eyes. \u0026ldquo;Cat, I think you are right.\u0026rdquo; She picked up the book. \u0026ldquo;The first thing we need is to get the content of this book into a vector.\u0026rdquo;\n(def odyssey-text (vec (slurp \u0026quot;odyssey.txt\u0026quot;))) (class odyssey-text) ;=\u0026gt; java.lang.PersistentVector \u0026ldquo;The vector contains all the characters. See, we can grab the first one and find its hash code this way.\u0026rdquo;\n(first odyssey-text) ;=\u0026gt; \\P (class (first odyssey-text)) ;=\u0026gt; java.lang.Character (.hashCode (first odyssey-text)) ;=\u0026gt; 80 \u0026ldquo;Now, all we need to do is to make a function to find the hash code and map it to the entire string.\u0026rdquo;\n(defn hashcode [c] (.hashCode c)) (map hashcode odyssey-text) ;=\u0026gt; (80 114 ..... ) \u0026ldquo;Next, we need to filter only the even ones out.\u0026rdquo;\n(defn hashcode [c] (.hashCode c)) (map hashcode odyssey-text) ;=\u0026gt; (80 114 111..... ) (filter even? (map hashcode odyssey-text)) ;=\u0026gt; (80 114 ... ) \u0026ldquo;Finally, we just need to sum all these values up with reduce.\u0026rdquo;\n(reduce + (filter even? (map hashcode odyssey-text))) ;=\u0026gt; 33702446 As soon as she had gotten her answer, Baba Yaga appeared back through the door. \u0026ldquo;Well, you seemed to have found the answer. But, let\u0026rsquo;s see how long it took you.\u0026rdquo;\n(dotimes [n 5] (println (str \u0026quot;map - filter - reduce - ( run \u0026quot; n \u0026quot; ):\u0026quot;)) (time (reduce + (filter even? (map hashcode odyssey-text))))) ;=\u0026gt; map - filter - reduce - ( run 0 ): ; \u0026quot;Elapsed time: 6932.227 msecs\u0026quot; ; map - filter - reduce - ( run 1 ): ; \u0026quot;Elapsed time: 5433.219 msecs\u0026quot; ; map - filter - reduce - ( run 2 ): ; \u0026quot;Elapsed time: 5157.45 msecs\u0026quot; ; map - filter - reduce - ( run 3 ): ; \u0026quot;Elapsed time: 5397.058 msecs\u0026quot; ; map - filter - reduce - ( run 4 ): ; \u0026quot;Elapsed time: 5224.334 msecs\u0026quot; Baba Yaga chuckled \u0026ldquo;Have it done again in under 5 seconds by the time I return. I am getting hungry.\u0026rdquo;\nThe girl starting sobbing again. \u0026ldquo;How am I supposed to make it faster?\u0026rdquo;\nThe cat calmly cleaned himself and said \u0026ldquo;I have heard that Clojure has a new Reducers library that allows you to do composable, parallel, reducible functions like mapping and filtering. Try this in the namespace.\u0026rdquo;\n(ns reducers.core (:require [clojure.core.reducers :as r])) \u0026ldquo;The new parallel versions of map and filter have the exact same shape as the regular versions. So all we need to do is use the new reducer versions.\u0026rdquo;\n(r/fold + (r/filter even? (r/map hashcode odyssey-text))) ;=\u0026gt; 33702446 \u0026ldquo;But, is it faster? The girl hoped.\u0026rdquo;\n;=\u0026gt; r/map - r/filter - r/fold - ( run 0 ): ; \u0026quot;Elapsed time: 4702.766 msecs\u0026quot; ; r/map - r/filter - r/fold - ( run 1 ): ; \u0026quot;Elapsed time: 4617.575 msecs\u0026quot; ; r/map - r/filter - r/fold - ( run 2 ): ; \u0026quot;Elapsed time: 4596.329 msecs\u0026quot; ; r/map - r/filter - r/fold - ( run 3 ): ; \u0026quot;Elapsed time: 4636.259 msecs\u0026quot; ; r/map - r/filter - r/fold - ( run 4 ): ; \u0026quot;Elapsed time: 4572.804 msecs\u0026quot; \u0026ldquo;No!\u0026rdquo; Baba Yaga stormed in the room. \u0026ldquo;Cat! You helped her! You mangy thing. Get out of here!\u0026rdquo; She shoved the cat out the door. \u0026ldquo;Let me look at that. I don\u0026rsquo;t believe it. I want to see the all the filtered hash values for myself.\u0026rdquo;\nThe cat peeked around the corner and spoke softly to the girl. \u0026ldquo;Luckily, into uses reduce.\u0026rdquo;\n(into [] (r/filter even? (r/map hashcode odyssey-text))) ;=\u0026gt; [80 114 ... ] While Baba Yaga was intently inspecting all the values in the vector, the cat motioned to the girl to slip out the door. Once outside, she grabbed the cat in her arms and ran as fast and as far away as she could. She was relieved to finally reach her home safely. Where she and cat lived happily for ever after writing Clojure code.\nThe End\nFor more information about Clojure Reducers For the code on github if you want to explore yourself. More about Baba Yaga Russian Fairy Tales.\n","permalink":"https://gigasquidsoftware.com/blog/2012/07/07/baba-yaga-and-the-clojure-reducers/","summary":"\u003cp\u003e\u003cimg alt=\"Baba Yaga\u0026rsquo;s House\" loading=\"lazy\" src=\"/images/posts/d912a829-BabaYaga3.GIF\"\u003e\u003c/p\u003e\n\u003cp\u003eOnce upon a time, a young girl decided to take a break from her code and stroll in the forest.  It was quite a pleasant day, she packed her lunch in her bag and set off.  While she was walking, she started thinking about a concurrency bug that her OO project was having.  As she pondered the complexities of mutablilty, state, and threads, she must of strayed from the trail and lost track of time.  By the time she looked around, she realized that she was totally lost.\u003c/p\u003e","title":"Baba Yaga and the Clojure Reducers"},{"content":"Do you need to have a specific version of Clojure in your leiningen project that you can\u0026rsquo;t get from Clojars?\nI ran into this problem when I wanted to run a sample project on Clojure\u0026rsquo;s reducers - which is not in the current Clojars version of 1.4.0. I needed to use the most recent version, (unreleased), of 1.5.0. These are the steps to get you running.\nClone the clojure git repository In the project directory - run ant to build the jar\nInstall the jar into your local maven repo\nmvn install:install-file -DgroupId=org.clojure -DartifactId=clojure -Dfile=clojure-1.5.0-master-SNAPSHOT.jar -DpomFile=pom.xml\nNow you can update your lein project.clj with (defproject reducers \u0026quot;1.0.0-SNAPSHOT\u0026quot; :description \u0026quot;FIXME: write description\u0026quot; :dependencies [[org.clojure/clojure \u0026quot;1.5.0-master-SNAPSHOT\u0026quot;]]) Run lein deps and you should be all set.\nThis trick also works with running leiningen projects with Datomic. In this case - download the Datomic library and from the root directory run mvn install:install-file -DgroupId=com.datomic -DartifactId=datomic -Dfile=datomic-0.1.3164.jar -DpomFile=pom.xml\n******* Update ******* I found out that there is already an alpha version of Clojure on Maven. So you don\u0026rsquo;t need to do the build. http://mvnrepository.com/artifact/org.clojure/clojure/1.5.0-alpha2\nIt would simply be (defproject reducers \u0026quot;1.0.0-SNAPSHOT\u0026quot; :description \u0026quot;FIXME: write description\u0026quot; :dependencies [[org.clojure/clojure \u0026quot;1.5.0-alpha2\u0026quot;]])\n","permalink":"https://gigasquidsoftware.com/blog/2012/07/07/how-to-include-non-clojars/maven-clojure-version-in-your-lein-project/","summary":"\u003cp\u003eDo you need to have a specific version of Clojure in your leiningen project that you can\u0026rsquo;t get from Clojars?\u003c/p\u003e\n\u003cp\u003eI ran into this problem when I wanted to run a sample project on Clojure\u0026rsquo;s reducers - which is not in the current Clojars version of 1.4.0.  I needed to use the most recent version, (unreleased), of 1.5.0.  These are the steps to get you running.\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003eClone the \u003ca href=\"https://github.com/clojure/clojure/\"\u003eclojure git repository \u003c/a\u003e\u003c/p\u003e","title":"How to include non clojars/maven clojure version in your lein project"},{"content":"In a day dream, I met a genie. He kindly offered to setup my dream dinner for me. All I had to do was name six guests and they would receive gilt invitations to the best restaurant in the world. Of course, they would all be delighted to attend and would be spared the nuisance of travel arrangements by handy magical teleportation. I hesitated for a moment, there are so many people that I would like to name. The genie tapped his foot impatiently. Alright here they are:\nPhilip Wadler\nDaniel Friedman\nRich Hickey\nPhilip Glass\nGeorge RR Martin\nNeil Gaiman\nWho would you name?\n","permalink":"https://gigasquidsoftware.com/blog/2012/05/04/day-dream-dinner/","summary":"\u003cp\u003eIn a day dream, I met a genie.  He kindly offered to setup my dream dinner for me.  All I had to do was name six guests and they would receive gilt invitations to the best restaurant in the world.  Of course, they would all be delighted to attend and would be spared the nuisance of travel arrangements by handy magical teleportation.  I hesitated for a moment, there are so many people that I would like to name.  The genie tapped his foot impatiently.  Alright here they are:\u003c/p\u003e","title":"Day Dream Dinner"},{"content":" I have had my Dualit Toaster for close to 19 years now. It has never broken down. It has reliably toasted my bread every morning with the mere turn of a dial.\nI have had my dishwasher for 1 year and 2 weeks. It has all sorts of cool buttons and modes so that I can customize my wash cycles to suit my dishes and my mood. Precisely two weeks after the warranty expired, it began to blink randomly and stopped working. The control board had died. This was not an isolated incident. I have gone through many such failures with other appliances, my refrigerator, stove and washing machine.\nLooking at my toaster and dishwasher, I made a couple of observations:\nThe more complex the product, the less reliable it is, and the shorter the life span. Sure, it would be cool if I could control my toaster with my mobile phone app, but just having a heating coil and a dial gives the advantage of having a lot less things that could go wrong.\nA product is only as reliable as its least reliable part. You can pay a small fortune for a oven built of stainless steel with all the latest technological advances in color display and computerized air flow. But if it relies on the same computer circuit board that all the other ovens use, (the one gives out after a year), then your investment is not any more reliable.\nI also noted that these observations could be translated to software as well. Certainly, in the case of building software, the more complex the system the more things that can go wrong. The same could hold true that overall software system is only as reliable as the least reliable part of it.\nThis brought me to the larger question.\nHow can they predict the dates so accurately? My dishwasher stopped working 2 weeks after the warranty ran out.\n— Carin Meier (@carinmeier) April 11, 2012\nHow do the manufacturers know, with such accuracy, when the product is going to fail? Could you apply the same principles to software?\n@carinmeier believe it or not they spend millions calculating it. I spent way too many hours in 6-sigma training with bathtub curves.\n— Jonathan Hays (@cheesemaker) April 11, 2012\nThe Bathtub Curve, according to wikipedia, is widely used in reliability engineering. It gets its name from the shape of the curve, which looks a bit like a bathtub. It is talked about in three sections:\nDecreasing failure rate (early failures)\nConstant failure rate (random failures)\nIncreasing failure rate (wear-out failures)\nWith software, we don\u0026rsquo;t talk about failures so much. We do talk about bugs, but even that is a bit misleading because it doesn\u0026rsquo;t take into account the need to accommodate features and evolving changes. So let\u0026rsquo;s talk about “issues” instead that can be broad enough to accommodate traditional bugs, gaps of functional needs, and performance related items.\nThe Software Bathtub Curve might look like the following:\nDecreasing issue rate (launch \u0026amp; growing pains)\nThis is the early stage of the software. After its initial launch, gaps in functionality, bugs, and performance issues are readily identified and corrected. The main factors of reliability here are communication, responsiveness and agility.\nSample questions for determining data for this part of the curve:\nDo you use a dynamic language/ framework that allows rapid development? +10\nIf the product owner and developers were in the same restaurant would they recognize each other? + 10\nCan the product owner and developers recognize each other by voice? +5\nDo you have a daily standup? + 5\nDo you really stand up the whole time? +2\nHow many outside integration points are there? -5 for each\nHow many programming languages and frameworks are there? -5 for each\nDo you release often? +5 for every 2 weeks (-1 for each week longer)\nDo you work over 40 hours a week regularly? -10\nDo you have an automated test suite? + 10\nDoes it have regularly have untended errors in it? -5\nDo you use pair programming or code reviews? +10\nConstant failure rate (random failures)\n****This is the time when the software reaches maturity. The business needs do not change drastically, but require minor refinements. Random issues occur from 3rd party integration issues or real world data issues. Major factors for reliability in this phase are avoidance of technical debt, data curation, and code quality.\nHas the team scaled down to just include a minimal or junior support staff? -10\nDo new features/ fixes get put in with the appropriate refactoring and tests? + 10\nDo new features/fixes more often just get stuck in there in the easiest way possible? -5\nDo your tests still all pass +10\nDo you get advance warning when a 3rd party api is changing? + 10\nDo you test that change in advance? + 5\nDo you still talk to the product owners? +5\nDo you care about code / data quality? + 10\nIncreasing failure rate (Failure to adapt to new business needs)\nThis is the final phase in the software life cycle. The new business needs cannot be met with the exsiting software and the cost of changing or adapting it is too high or not possible. Major factors for reliability and length of life span include openness and complexity of design and architecture.\nDo you have have to pay for a closed vendor product? -10\nDo you use open source languages and libraries? + 10\nAre you afraid to change anything because it might break? -10\nIs your main software language more than 1 version behind the latest? -5 for each version behind\nDoes the mention of new features install fear instead of passion? -500\nIn the end, although it is interesting to compare software to the appliance Bathtub Curve, it is a leaky abstraction at best (sorry, couldn\u0026rsquo;t resist). Software is living thing. It needs to respond to its ever changing environment and needs. Furthermore, it is made up of a collection of living people who care and tend for it as well. However, there are clear factors that can go a long way to increasing the reliability, usability, and lifespan of software as well. We, as software developers, should keep them in mind as part of the ultimate goal of creating living, quality software.\n","permalink":"https://gigasquidsoftware.com/blog/2012/04/12/the-software-bathtub-curve/","summary":"\u003cfigure class=\"left\"\u003e\n    \u003cimg loading=\"lazy\" src=\"/images/posts/6577e16c-9925846584_3bf93b2cca.jpg\"/\u003e \n\u003c/figure\u003e\n\n\u003cp\u003eI have had my Dualit Toaster for close to 19 years now. It has never broken down. It has reliably toasted my bread every morning with the mere turn of a dial.\u003c/p\u003e\n\u003cp\u003eI have had my dishwasher for 1 year and 2 weeks. It has all sorts of cool buttons and modes so that I can customize my wash cycles to suit my dishes and my mood. Precisely two weeks after the warranty expired, it began to blink randomly and stopped working. The control board had died. This was not an isolated incident. I have gone through many such failures with other appliances, my refrigerator, stove and washing machine.\u003c/p\u003e","title":"The Software Bathtub Curve"},{"content":"I was delighted to see first hand, why 1200 CodeMash tickets sold out in 20 minutes. It was full of awesome. This was easily the biggest conference that I have ever attended. It was held in the luxurious and fun Kalahari conference center and ran as smooth as silk, expertly supported by a volunteer staff.\nOne of the things that I really appreciated about the conference was the diversity of people from different technology backgrounds. There were many developers from .NET, Java, Ruby, and Python worlds all coming together to swap stories, share ideas and learn something new. It created an opportunity for everyone to get out of their box and their comfort zone. I was particularly impressed by one woman that I talked to, who came from the .NET world but had made a conscious decision to not attend any .NET talks at all.\nThe talks that I attended were all superb. Here is a few of my personal highlights:\nJim Weirich\u0026rsquo;s Roman Numeral Code Kata: He did a live coding demonstration of the Roman Numeral kata by TDD and refactoring. The joy that he shows when his tests turn green and the love of the beauty of the code that emerges from refactoring, embody for me what Software Craftsmanship is all about. He simply is an inspiration.\nJoshua Smith\u0026rsquo;s Prolog Talk: An excellent talk by and excellent speaker. He demonstrated the basics of Prolog reasoning by doing a family tree example. I am intrigued by it\u0026rsquo;s use with Semantic Web RDF reasoning and it\u0026rsquo;s similarity to Clojure\u0026rsquo;s core.logic. It is top of my list of things to look into.\nJen Myer\u0026rsquo;s Developers Can\u0026rsquo;t Design: She touched a chord for me, since I wish that I had more design skill. She masterfully pointed out the similarities of solving problems in design just as we solve problems in code development. Another key take away for me, was the need to have a holistic design for our applications. Siloing designers in Photoshop and then having developers take it from there is reminiscent of failed waterfall patterns. Embracing holistic design feedback at all levels of the project is needed to produce excellent applications.\n**Elizabeth Naramore\u0026rsquo;s Building Open Source Communities: ** This talk was a gem. She touched on the importance of Open Source communities by focusing on it\u0026rsquo;s essential component – people. Communication is so important in facilitating the flow of ideas that turns into the magic that fuels a vibrant community. One of her points, that I took away is to remember it is the little things that count. Don\u0026rsquo;t forget to say “Thank you.”\nAnother thing that delighted me was the strong interest in Clojure that was present at the conference. I had the good fortune to present an introduction to Clojure and I was so happy to talk to many people during the conference that said that they were interested in learning more at the language. There was even an Open Space that got spontaneously organized on Clojure on Friday.\nThe only downside of the conference was that it was hard to choose between the Open Spaces and the excellent talks going on. I did attend one that Justin Searls hosted on Friday afternoon. It was a blast. People paired up creating a simple JavaScript To Do app from different frameworks. John Andrews and I took the opportunity to explore ClojureScript. In particular, we played around with the new ClojureScript One and also the Enfocus library. At the end of the hour, we were having so much fun, I wished that we had another day just to continue.\nAll in all, it was an awesome time and I recommend it highly. If I had to sum it up in a phrase it would be: Bacon for the Brain :)\n","permalink":"https://gigasquidsoftware.com/blog/2012/01/14/code-mash-2012-bacon-for-the-brain/","summary":"\u003cp\u003eI was delighted to see first hand, why 1200 \u003ca href=\"http://codemash.org/\"\u003eCodeMash\u003c/a\u003e tickets sold out in 20 minutes. It was full of awesome. This was easily the biggest conference that I have ever attended. It was held in the luxurious and fun Kalahari conference center and ran as smooth as silk, expertly supported by a volunteer staff.\u003c/p\u003e\n\u003cp\u003eOne of the things that I really appreciated about the conference was the diversity of people from different technology backgrounds. There were many developers from .NET, Java, Ruby, and Python worlds all coming together to swap stories, share ideas and learn something new. It created an opportunity for everyone to get out of their box and their comfort zone. I was particularly impressed by one woman that I talked to, who came from the .NET world but had made a conscious decision to not attend any .NET talks at all.\u003c/p\u003e","title":"Code Mash 2012: Bacon for the Brain"},{"content":"Only one more day until CodeMash. I am really looking forward to my first one. I have heard nothing but wonderful things about this conference that brings together developers, geeks and their families for a week in January in Sandusky, Ohio.\nI am also looking forward to the opportunity of presenting my \u0026ldquo;Once Upon a Time in Clojureland\u0026rdquo; talk. It is an introduction to Clojure in a Fairy Tale format. I am hoping to share my enthusiasm for the language and inspire others to try it out for themselves.\nIf you haven\u0026rsquo;t seen it, you should check out the Mashed Code Magazine. It is full of awesome. It also contains a piece that I wrote under my super secret identity. Hint, it is about Monads :)\nWell off to pack and get things organized. I\u0026rsquo;ll post my full coverage in the following days \u0026hellip;\n","permalink":"https://gigasquidsoftware.com/blog/2012/01/10/getting-ready-for-codemash/","summary":"\u003cp\u003eOnly one more day until \u003ca href=\"http://codemash.org/\"\u003eCodeMash\u003c/a\u003e.  I am really looking forward to my first one.  I have heard nothing but wonderful things about this conference that brings together developers, geeks and their families for a week in January in Sandusky, Ohio.\u003c/p\u003e\n\u003cp\u003eI am also looking forward to the opportunity of presenting my \u0026ldquo;Once Upon a Time in Clojureland\u0026rdquo; talk.  It is an introduction to Clojure in a Fairy Tale format.  I am hoping to share my enthusiasm for the language and inspire others to try it out for themselves.\u003c/p\u003e","title":"Getting Ready for CodeMash"},{"content":"\nOne important measure of a country\u0026rsquo;s economy is it\u0026rsquo;s technology. Most current technology indexes for countries rely on boring statistics like R\u0026amp;D spending and internet availability. I think that these measures are totally inadequate. To really gauge whether a country is technologically advanced, you need to take a hard look at stupid, pointless, and amusing things produced on the internet.\nAs an alternative, I would like to announce the Nyan Cat Country Technology Index. For those of you who have not heard of Nyan Cat. It is a internet meme that combines a flying Pop Tart cat trailing rainbows and a strange Japanese song.\nNyan Cat is a perfect example of stupid, pointless, and amusing. What\u0026rsquo;s more, it has spread like wildfire and infected many countries, resulting in various inspired patriotic versions of the video. This perfect storm of elements have combined to yield a striking new perspective of national technology.\nI have used my expert experience in Nyan Cat, honed after many days of bombardment in our Campfire room at work, and my own quirky taste, to view and judge the countries that were prominent on YouTube.\nNyan Cat Country Technology Index\nTied: US \u0026amp; Japan. Come on they started the whole thing. Of course, they are first. Original Video\nUK : Scottish and Irish Nyan Cats moved the UK to the 2nd place. They are superb. Notice the folded ears on the Scottish Nyan Cat. Britan could have tried harder.\n* [Scottish Nyan Cat](http://www.youtube.com/watch?v=M0Orj3J4eCY) * [Irish Nyan Cat](http://www.youtube.com/watch?v=li8ewiacEi0) * [British Nyan Cat](http://www.youtube.com/watch?v=v71P-svS350) German Nyan Cat\nFrench Nyan Cat- Extra points for the wine and Mona Lisa. Music missing Nya\nPolish Nyan Cat– Love the Hussar wings – but points off for no Nya music.\nDutch Nyan Cat– Again, nice rain but wrong music.\nHungarian Nyan Cat– Nice music .. but not really a cat.\nRussian Nyan Cat\nAustralian Nyan Cat\nCanada Nyan Cat\nIndian Nyan Cat\nPhilipppine Nyan Cat\nChinese Nyan Cat\nBelgium Nyan Cat\nGreek Nyan Cat\nIf your country was not included on the list. By all means, go out a create a video right away. Your nation\u0026rsquo;s future is depending on you. If your country has a Nyan Cat video on YouTube and was not included, I apologize on behalf of all the brain cells that were killed in assembling this list.\nAddendum: I have to admit that the Nyan Cat has grown on me, especially since my office mates have turned off their Campfire sounds. I am hereby editing the post to remove the annoying adjective, but the stupid, pointless and amusing adjectives remain :)\n","permalink":"https://gigasquidsoftware.com/blog/2012/01/04/nyan-cat-country-technology-index/","summary":"\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/images/posts/a49f0e36-9925780995_b507b30d9a_o.png\"\u003e\u003c/p\u003e\n\u003cp\u003eOne important measure of a country\u0026rsquo;s economy is it\u0026rsquo;s technology. Most current technology indexes for countries rely on boring statistics like R\u0026amp;D spending and internet availability. I think that these measures are totally inadequate. To really gauge whether a country is technologically advanced, you need to take a hard look at stupid, pointless, and amusing things produced on the internet.\u003c/p\u003e\n\u003cp\u003eAs an alternative, I would like to announce the Nyan Cat Country Technology Index. For those of you who have not heard of Nyan Cat. It is a \u003ca href=\"http://en.wikipedia.org/wiki/Nyan_Cat\"\u003einternet meme\u003c/a\u003e that combines a flying Pop Tart cat trailing rainbows and a strange Japanese song.\u003c/p\u003e","title":"Nyan Cat Country Technology Index"},{"content":" White: a Blank Page or Canvas.\nAs I spent a pleasant Sunday outside doing yard work, songs from one of my favorite musicals, “Sunday in the Park with George”, came to mind. While the songs were playing in my head, my thoughts again drifted to one of my favorite programming languages, Clojure. To my surprise, I was struck by similarities between the musical, which is about the artist Geroges Seuret and his creation of one of his famous painting, and that of the functional JVM language of Clojure. Granted, musicals, art and programming languages don\u0026rsquo;t generally get discussed together, but please humor me and let me elaborate. Following the thread of my inspiration, I will be using the first few opening lines from the musical as my headings and guides for my discussion.\nLet\u0026rsquo;s start with the broad subjects of Art and Software. They are both created. We use our tools, palettes and techniques to create representations of the world. The visual artist portrays this representation in paints and on canvas, while the software developer uses programming languages and computers.\nLooking back in time, we see that there are many different styles of painting that have developed over time. From flat, idealized Byzantine Art to that of the incredible realistic detail of Renaissance Dutch portrait masters. These styles were a reflection of not only the techniques and materials of the time, but also an outlook on the world and the way the artist represented it. Likewise, software styles also have differed over time. From the procedural BASIC language to the current dominant style of Object Oriented programming, the styles are a reflection of not only the technology available to us, but in the way that we model real world concepts and processes into the digital space.\nThe Challenge: Bring Order to the Whole. Georges Seuret was interested in the optic effect when two small points of different color placed close to one another, would seem to create a third new and luminous color when viewed at a distance. He innovated a technique called pointillism, and created a whole painting composed of tiny dots of color. The striking effect of this can be seen in his famous, large scale painting titled \u0026ldquo;A Sunday Afternoon on the Island of La Grande Jatte”.\nIn his use of pointillism, Seuret turned to simplicity to create order and achieve complexity. By breaking the painting down into the essence of dots of colors, he opened the way for a sort of parallelism in color viewing by the user, which ended up giving the viewer a perception of richer colors. This very technique, enhanced by todays technology is of course the basis of our incredible RGB viewing in our televisions and monitors.\nLet\u0026rsquo;s turn to Clojure. Clojure is a functional language that is interested with concurrency. It also turns to simplicity to achieve complexity. By breaking things down and simplifying to more pure functions with immutable data structures, it make the complex problem of parallel programming possible. This is something that is very hard in the Object Oriented world view programming model. In my opinion, Clojure\u0026rsquo;s approach to concurrent complexity with simplicity is an important innovation to our world of software, just as pointillism was to the world of art. To better explain, let\u0026rsquo;s walk though some of the language features.\nThrough Design Rich Hickey designed Clojure as a general-purpose language. He wanted it to combine some of best parts of a scripting language – the approachability and interactive development with a REPL – with an infrastructure that would be fast, robust and support multithreaded programming.\nComposition The language itself is a LISP. It gains the benefits of the simplicity of syntax of the code as data as well as having the power of Macros that allows one to customize the language. The beauty of this simplicity and conciseness allows one to focuses more on the code that matters.\nTension Pure functions and immutable state is great, but to most things you will need some sort of state. Clojure also provides ways to use mutable state and still support correct multithreaded designs. It uses Software Transaction Memory System and Agents to achieve this. This use of mutable state in a controlled and isolated way, allows clean, efficient and concurrent programming.\nBalance Clojure embraces the JVM as it\u0026rsquo;s platform. This pragmatic approach gives not only gives the language a scalable, proven run time environment, it also gives it the advantage of accessing Java\u0026rsquo;s many mature libraries through wrapper free interoperability.\nLight Clojure language is a joy to learn. Being concise and a LISP, is very regular in it\u0026rsquo;s syntax. There are only a few key data structures and forms to learn to really get started.\nand Harmony. Clojure has an awesome community. The level of enthusiasm and innovation among the Clojure open source developers is inspiring. Every day seems to bring a new development or contribution. There is ClojureScript for JavaScript development, Noir for web development, Logic programming just to name a few.\nIn summary, innovation in art and technology can come through a quest for simplification. This very act of simplification, then allows for breakthroughs in complexity. Both Seuret and Hickey have shared in this vision in both their art and software.\nFinally, I highly recommend watching “Sunday in the Park with George” if you haven\u0026rsquo;t seen it yet. I also highly recommend looking at Clojure too. In fact, you might want to try some Clojure Koans before watching the show. You might enjoy it from a different perspective\u0026hellip;\n","permalink":"https://gigasquidsoftware.com/blog/2011/09/13/sunday-in-the-park-with-george-and-clojure/","summary":"\u003ch1 id=\"heading\"\u003e \u003c/h1\u003e\n\u003cfigure class=\"left\"\u003e\n    \u003cimg loading=\"lazy\" src=\"/images/posts/1a289219-9925803956_c92c63045e_o.jpg\"/\u003e \n\u003c/figure\u003e\n\n\u003cp\u003eWhite: a Blank Page or Canvas.\u003c/p\u003e\n\u003cp\u003eAs I spent a pleasant Sunday outside doing yard work, songs from one of my favorite musicals, \u003ca href=\"http://en.wikipedia.org/wiki/Sunday_in_the_Park_with_George\"\u003e“Sunday in the Park with George”\u003c/a\u003e, came to mind. While the songs were playing in my head, my thoughts again drifted to one of my favorite programming languages, Clojure. To my surprise, I was struck by similarities between the musical, which is about the artist Geroges Seuret and his creation of one of his famous painting, and that of the functional JVM language of Clojure. Granted, musicals, art and programming languages don\u0026rsquo;t generally get discussed together, but please humor me and let me elaborate. Following the thread of my inspiration, I will be using the first few opening lines from the musical as my headings and guides for my discussion.\u003c/p\u003e","title":"Sunday in the Park with George and Clojure"},{"content":"Long ago, I worked for a couple years as a professional ballet dancer with a small company. Reflecting on this, I have an interesting perspective of working in field were woman are the majority and also one where women are in the minority. I thought I would dedicate this post a few observations of similarities between men in ballet and women in software development.\nMen in Ballet Have some lame people think ballet is just for girls and make assumptions about them based on cultural stereotypes\nHave to have a sense of humor to handle accidentally injuries due to kicks or slips while rehearsing choreography with women.\nClearly love what they do. Otherwise, they most likely would have never overcome the social pressure to pursue their craft.\nPartner when ballerinas to create great performances. The diversity of having men and women dance together allows more freedom of expression in the choreography. Ultimately, that produces a show that is more valuable and pleasing to the audience.\nUsually have no wait in line for the men\u0026rsquo;s restroom during ballet performance intermissions.\nWomen in Software Development\nHave some lame people think software development is just for boys and make assumptions about them based on cultural stereotypes.\nHave to have a sense of humor to handle accidental insensitive remarks due to slips in conversation when working with men. (Ex: hot chicks, rude jokes, etc\u0026hellip;.)\nClearly love what they do. Otherwise, they most likely would have never overcome the social pressure to pursue their craft.\nPartner with other software developers to create great software. More diversity*, allows more freedom of expression in understanding and applying technology to solve business needs. Ultimately, that produces software that is more valuable and pleasing to the business and user.\nUsually have no wait in line for the women\u0026rsquo;s restroom during technical conference breaks.\n*And yes, the diversity I am talking about is not limited to just men and women.\n","permalink":"https://gigasquidsoftware.com/blog/2011/08/20/on-men-in-ballet-and-women-in-software-development/","summary":"\u003cp\u003eLong ago,  I worked for a couple years as a professional ballet dancer with a small company. Reflecting on this, I have an interesting perspective of working in field were woman are the majority and also one where women are in the minority. I thought I would dedicate this post a few observations of similarities between men in ballet and women in software development.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eMen in Ballet\u003c/strong\u003e\n\u003cfigure class=\"left\"\u003e\n    \u003cimg loading=\"lazy\" src=\"/images/posts/a24ae98d-9925846994_2673f8183c_o.jpg\"/\u003e \n\u003c/figure\u003e\n\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003eHave some lame people think ballet is just for girls and make assumptions about them based on cultural stereotypes\u003c/p\u003e","title":"On Men in Ballet and Women in Software Development"},{"content":"Since joining EdgeCase, I have shelved my heavy Intellij and Eclipse IDEs in favor of Emacs. Overall, I have enjoyed moving to the light-weight but powerful editor. There is one thing that I did miss from my IDEs – that was the ability to search projects for string occurrences and being able to click navigate to them through the editor. Fortunately, one of the strengths of Emacs is it\u0026rsquo;s infinite configurability and extensibility. Even more fortunate, one of the guys in our shared office, Doug Alcorn of Gaslight Software, had already written just this feature for his Emacs. I installed it and was so pleased with it, that I thought I would share …\nhttps://github.com/dougalcorn/emacs.d/blob/master/site-lisp/misc/project-grep.el\nTo install: Download project-local-variables.el and project-grep.el In your init.el file: (require \u0026lsquo;project-grep) Create an empty .emacs-project file in your directory\nTo use: meta-x project-grep\n","permalink":"https://gigasquidsoftware.com/blog/2011/08/13/project-grep-another-sharp-tool-for-your-emacs/","summary":"\u003cp\u003eSince joining EdgeCase, I have shelved my heavy Intellij and Eclipse IDEs in favor of Emacs. Overall, I have enjoyed moving to the light-weight but powerful editor. There is one thing that I did miss from my IDEs – that was the ability to search projects for string occurrences and being able to click navigate to them through the editor. Fortunately, one of the strengths of Emacs is it\u0026rsquo;s infinite configurability and extensibility. Even more fortunate, one of the guys in our shared office, \u003ca href=\"http://twitter.com/#!/dougalcorn\"\u003eDoug Alcorn\u003c/a\u003e of Gaslight Software, had already written just this feature for his Emacs. I installed it and was so pleased with it, that I thought I would share …\u003c/p\u003e","title":"Project-Grep : Another Sharp Tool for your Emacs"},{"content":"I got the chance to share my enthusiasm for two of my favorite technologies at JRubyConf by giving a presentation on Semantic Web and JRuby. It was an excellent experience. I was able to connect with other people that shared my interest in the Semantic Web and some that have even worked with the technologies professionally. Most exciting, I had the opportunity to share my knowledge and hopefully inspire others to look farther into using JRuby with the Jena Semantic Web Framework.\nHere are some resources from the presentation that I wanted to share with everyone:\nOn github, https://github.com/gigasquid/jruby_semantic_web_examples, I put together some examples of SPARQL queries against dbpedia as well as translating the examples that they have on the Jena RDF API to use JRuby\nHere is the presentation itself: https://github.com/gigasquid/Presentations/blob/master/SemanticWebJRuby.pdf\nA special note of thanks to Brian Sletten, the Semantic Web guru, who inspired and exposed me to the Semantic Web, helped me out by answering my questions and pointing me in the right direction and for just being a swell guy.\n","permalink":"https://gigasquidsoftware.com/blog/2011/08/08/semantic-web-and-jruby/","summary":"\u003cp\u003eI got the chance to share my enthusiasm for two of my favorite technologies at JRubyConf by giving a presentation on Semantic Web and JRuby. It was an excellent experience. I was able to connect with other people that shared my interest in the Semantic Web and some that have even worked with the technologies professionally. Most exciting, I had the opportunity to share my knowledge and hopefully inspire others to look farther into using JRuby with the Jena Semantic Web Framework.\u003c/p\u003e","title":"Semantic Web and JRuby"},{"content":"Deploying Clojure apps with a single command to the cloud is now possible with Heroku Cedar and let me tell you, it is pure joy.\nI experimented with this the other day by creating a Compojure web application that compares the followers that two twitter users have in common.\nHere is the secret sauce you need to push your apps to Heroku:\n**Procfile: ** You need to create a file in the root of your directory that contains the way to start up your application:\nweb: lein run -m ring-twitter-common.core\nThe application must have the project.clj setup correctly so that you can just run:\nlein deps\nYou need to install the Heroku gem\nOnce you have this setup you simply do:\nheroku create --stack cedar git push heroku master That\u0026rsquo;s it. Your webapp will auto-magically be created, and deployed and be available for your viewing pleasure.\nYou can check out my sample Twitter Heroku app here: http://ring-twitter-common.herokuapp.com/\nBut wait, you say\u0026hellip; wouldn\u0026rsquo;t it be awesome if you could just write your Clojure app and say lein deploy and have it all work? Wouldn\u0026rsquo;t it be super awesome if there was some command to generate a skeleton for your Compojure app? The solution is actually in the planning stages by James Reeves (weavejester)! Hooray!\nLeiningen Google Group Text\nIn summary: Developing Clojure Web Apps just got easier and the future is only looking up :)\n","permalink":"https://gigasquidsoftware.com/blog/2011/06/11/super-easy-clojure-web-apps-with-heroku-cedar/","summary":"\u003cp\u003eDeploying Clojure apps with a single command to the cloud is now possible with Heroku Cedar and let me tell you, it is pure joy.\u003c/p\u003e\n\u003cp\u003eI experimented with this the other day by creating a Compojure web application that compares the followers that two twitter users have in common.\u003c/p\u003e\n\u003cp\u003eHere is the secret sauce you need to push your apps to Heroku:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e\n\u003cp\u003e**Procfile: **\nYou need to create a file in the root of your directory that contains the way to start up your application:\u003c/p\u003e","title":"Super Easy Clojure Web Apps with Heroku Cedar"},{"content":"I have been happily using Jasmine and Jasmine-JQuery on a project with great success. However, I was still unsure about how to handle mocking the ajax calls back to the server. It turns out the answer is already in Jasmine. Time to call out the spies!\nThere is a wiki page on spies https://github.com/pivotal/jasmine/wiki/Spies, but I always enjoy a nice code sample.\nIn my source file I have an ajax call that I would like to mock that looks like this: [gist id=957387]\nNow in my spec file - I setup a spy on the ajax call and use andCallFake to mock the call. When the method is tested, the ajax call will be mocked and return through the success handler. You can pass data back through the fakeData var. [gist id=957389]\n","permalink":"https://gigasquidsoftware.com/blog/2011/05/05/mocking-ajax-calls-with-jasmine/","summary":"\u003cp\u003eI have been happily using \u003ca href=\"https://github.com/pivotal/jasmine/\"\u003eJasmine\u003c/a\u003e and \u003ca href=\"https://github.com/velesin/jasmine-jquery\"\u003eJasmine-JQuery\u003c/a\u003e on a project with great success. However, I was still unsure about how to handle mocking the ajax calls back to the server. It turns out the answer is already in Jasmine. Time to call out the spies!\u003c/p\u003e\n\u003cp\u003eThere is a wiki page on spies \u003ca href=\"https://github.com/pivotal/jasmine/wiki/Spies\"\u003ehttps://github.com/pivotal/jasmine/wiki/Spies\u003c/a\u003e, but I always enjoy a nice code sample.\u003c/p\u003e\n\u003cp\u003eIn my source file I have an ajax call that I would like to mock that looks like this:\n[gist id=957387]\u003c/p\u003e","title":"Mocking Ajax Calls with Jasmine"},{"content":"Lately, I have been working on the awesome open source project 4Clojure.com. The site helps you to learn Clojure by solving “koan” type problems in an interactive format. One of the enhancements that I was looking at putting in was a way to enter code in a text box and have it color highlight as type. I found the ACE project, which looked like exactly what I wanted. However, sad panda, they didn\u0026rsquo;t have a Clojure mode. Not deterred, I decided that I would try to take a crack at it. I ported most of the rules from the Clojure brush in Syntax Highlighter over and implemented some basic auto-indent.\nThe Github source has been added to the main project at Ace https://github.com/ajaxorg/ace You can see it in action on the 4Clojure.com site here: http://www.4clojure.com/problem/14\n","permalink":"https://gigasquidsoftware.com/blog/2011/05/01/hacking-javascript-for-the-love-of-clojure/","summary":"\u003cp\u003eLately, I have been working on the awesome open source project \u003ca href=\"http://www.4clojure.com/\"\u003e4Clojure.com\u003c/a\u003e. The site helps you to learn Clojure by solving “koan” type problems in an interactive format. One of the enhancements that I was looking at putting in was a way to enter code in a text box and have it color highlight as type. I found the \u003ca href=\"http://ace.ajax.org/\"\u003eACE project\u003c/a\u003e, which looked like exactly what I wanted. However, sad panda, they didn\u0026rsquo;t have a Clojure mode. Not deterred, I decided that I would try to take a crack at it. I ported most of the rules from the Clojure brush in Syntax Highlighter over and implemented some basic auto-indent.\u003c/p\u003e","title":"Hacking JavaScript for the Love of Clojure"},{"content":"I have put a couple projects out on GitHub to help people get started with Clojure and Ruby. The Katas are taken more or less from the Coding Kata site http://codingkata.org/katas/. The projects both include the basic project setup for you to get started with TDD beginner katas.\nThe Ruby project has tests in the form of rspec-given, which is quite fun. The Clojure project has tests in the form of Midje, which has a lovely syntax.\nPlease give them a try :)\nhttps://github.com/gigasquid/yellow_belt_ruby_katas https://github.com/gigasquid/yellow_belt_clojure_katas\n","permalink":"https://gigasquidsoftware.com/blog/2011/04/16/yellow-belt-katas-for-ruby-and-clojure/","summary":"\u003cp\u003eI have put a couple projects out on GitHub to help people get started with Clojure and Ruby.\nThe Katas are taken more or less from the Coding Kata site \u003ca href=\"http://codingkata.org/katas/\"\u003ehttp://codingkata.org/katas/\u003c/a\u003e. The projects both include the basic project setup for you to get started with TDD beginner katas.\u003c/p\u003e\n\u003cp\u003eThe Ruby project has tests in the form of rspec-given, which is quite fun. The Clojure project has tests in the form of Midje, which has a lovely syntax.\u003c/p\u003e","title":"Yellow Belt Katas for Ruby and Clojure"},{"content":"\n(*Sketch By My Awesome Husband)\n","permalink":"https://gigasquidsoftware.com/blog/2011/04/12/knights-who-say-monad/","summary":"\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/images/posts/f141cdbc-9925781235_e80904a961_o.jpg\"\u003e\u003c/p\u003e\n\u003cp\u003e(*Sketch By My Awesome Husband)\u003c/p\u003e","title":"Knights Who Say Monad"},{"content":"Recently, I decided to work on a set of code Katas. I couldn\u0026rsquo;t decide whether to do them in Ruby or Clojure, so I decided to do them in both. I did the Kata in Ruby first and then immediately followed up with the same one in Clojure. It was an interesting exercise, not only for the learning of the languages, but to highlight how I thought about the problems differently depending on the language.\nRuby is a fantastic language. It would delight and sometimes surprise me with how elegant and natural it was to solve problems. When I approached the Kata, I found myself thinking, “How can I make this more readable?”. Ruby never failed to please.\nClojure is also a wonderful language. One of the things that I really enjoy about it is that it changed that way that I approach problems. This was particularly evident when I turned to solve the same problem in Ruby that I just had in Clojure. First and foremost, I thought about the data. Then about how the data could be transformed. The transformation isn\u0026rsquo;t like the serial steps that you normally take to hold the data in your hand and bit by bit mold it into the result – like a sculptor with clay. It is the kind of transformation that takes a rolled ball of yarn and transforms into a beautiful lace pattern.\nThe closest that I had come to this functional way of thinking was when I was doing some heavy SQL and database work. I went to a talk by Jay Pipes on MySQL. I remember him saying that to be really good at SQL, you needed to think in sets. You couldn\u0026rsquo;t effectively solve the queries with the regular programming for-loop construct. You needed to think of the sets of data joining and intersecting and the transformations needed to be applied to the data elements. The same focus on the data seemed to hold true for Clojure too.\nI highly recommend both Ruby and Clojure as programming languages. Each are dynamic, elegant and powerful and a lot of fun. Next time you sit down to do a Kata, and can\u0026rsquo;t decide what language to use, try them both – and let me know how you think\u0026hellip;\n","permalink":"https://gigasquidsoftware.com/blog/2011/04/08/on-thinking-in-ruby-and-clojure/","summary":"\u003cp\u003eRecently, I decided to work on a set of code Katas.  I couldn\u0026rsquo;t decide whether to do them in Ruby or Clojure, so I decided to do them in both.  I did the Kata in Ruby first and then immediately followed up with the same one in Clojure.  It was an interesting exercise, not only for the learning of the languages, but to highlight how I thought about the problems differently depending on the language.\u003c/p\u003e","title":"On Thinking in Ruby and Clojure"},{"content":"We took our kids bowling for the first time the other day. I have to admit, that I am not a great bowler. I had only been bowling two or three times in my life previous to that event and I was very thankful that those bumpers were up. The computer program malfunctioned in the final frames of our last game. I realized then, that I really had no idea how to score bowling. Later that night, in my surfing, I came across a reference to the Bowling Game Kata.\nSuch Kata serendipity could not be ignored. I decided to implement it in Clojure using defrecords to mimic the object model with Frames and the Game and use STM to keep the state of the Game in an atom. Finally, the unit tests are using Midje facts – which has a syntax that I enjoy.\nAll in all, it was a great learning exercise and as a bonus\u0026hellip; I know how to score a bowling game now!\n","permalink":"https://gigasquidsoftware.com/blog/2011/03/01/bowling-game-kata-in-clojure-with-stm-and-defrecord/","summary":"\u003cp\u003eWe took our kids bowling for the first time the other day. I have to admit, that I am not a great bowler. I had only been bowling two or three times in my life previous to that event and I was very thankful that those bumpers were up. The computer program malfunctioned in the final frames of our last game. I realized then, that I really had no idea how to score bowling. Later that night, in my surfing, I came across a reference to the \u003ca href=\"http://butunclebob.com/ArticleS.UncleBob.TheBowlingGameKata\"\u003eBowling Game Kata\u003c/a\u003e.\u003c/p\u003e","title":"Bowling Game Kata in Clojure with STM and defrecord"},{"content":"In Part 1, we used defrecords to create a vampire slayer named “Buffy” and a few vampires for her to kick around. Today we are going to use Buffy and her vampires to explore STM (Software Transactional Memory) in Clojure for managing state.\nRecap\n(defrecord Vampire [name, health]) (def vampire1 (Vampire. \u0026quot;Stu\u0026quot; 50)) (def vampire2 (Vampire. \u0026quot;Vance\u0026quot; 100)) (def vampire3 (Vampire. \u0026quot;Izzy\u0026quot; 75)) (defrecord Slayer [name, weapon]) (def kungfu 25) (def buffy (Slayer. \u0026quot;Buffy\u0026quot; kungfu)) (defn hit [vampire, hitpoints] (- (:health vampire) hitpoints)) ;vampires don't fight back but it takes time to kill them (def combat-time 20) (defn hit-vampire [vampire, slayer] (Thread/sleep (* combat-time 10)) (assoc vampire :health (hit vampire (:weapon slayer)))) (defn kill-vampire [vampire, slayer] (if (\u0026gt; (:health vampire) 1) (recur (hit-vampire vampire slayer) slayer) (assoc vampire :health 0))) Let\u0026rsquo;s take our vampires and stand them up in a line for Buffy to fight. We are also going to create a function that just has Buffy killing a vampire, rather then a generic slayer.\n(def vampire-line [vampire1 vampire2 vampire3]) (defn buffy-kill-vampire [vampire] (kill-vampire vampire buffy)) Test Buffy killing vampire1\n(buffy-kill-vampire vampire1) #:user.Vampire{:name \u0026quot;Stu\u0026quot;, :health 0} Now we can use the map function to apply the buffy-kill-vampire function to every vampire in our vampire line.\n(map buffy-kill-vampire vampire-line) (#:user.Vampire{:name \u0026quot;Stu\u0026quot;, :health 0} #:user.Vampire{:name \u0026quot;Vance\u0026quot;, :health 0} #:user.Vampire{:name \u0026quot;Izzy\u0026quot;, :health 0}) This is also a good time to bring up pmap (pmap f coll). The pmap is the same as the map execpt that it applys the function to the collection in parallel. It is useful when the time to process each function is computationally intensive. To show the difference between map and pmap let\u0026rsquo;s change the combat-time to be 200ms instead of 20ms and time each way. We need a dorun to force the function to not be lazy.\n(def combat-time 200) (time (dorun (map buffy-kill-vampire vampire-line))) \u0026quot;Elapsed time: 18002.67764 msecs\u0026quot; (time (dorun (pmap buffy-kill-vampire vampire-line))) \u0026quot;Elapsed time: 8001.808821 msecs Now if you notice, even though we have be killing the vampire line over and over again. They don\u0026rsquo;t stay dead\nvampire-line [#:user.Vampire{:name \u0026quot;Stu\u0026quot;, :health 50} #:user.Vampire{:name \u0026quot;Vance\u0026quot;, :health 100} #:user.Vampire{:name \u0026quot;Izzy\u0026quot;, :health 75}] We need to involve some state so that our vampire-line will reflect the health of zero for all of the vampires once Buffy slays them. In Clojure, state is handled by Software Transactional Memory (STM). You can use Refs for coordinated and synchronous updates, Atoms for Uncoordinated and Synchronous updates, or Agents for asynchronous updates. In our example, we are going to use the Atom, since it is lighter weight and we just want to maintain the state of the vampire-line.\nLet\u0026rsquo;s refine the vampire-line as an atom. We\n(def vampire-line (atom [vampire1 vampire2 vampire3])) We need to deference it now to know it\u0026rsquo;s value\n@vampire-line [#:user.Vampire{:name \u0026quot;Stu\u0026quot;, :health 50} #:user.Vampire{:name \u0026quot;Vance\u0026quot;, :health 100} #:user.Vampire{:name \u0026quot;Izzy\u0026quot;, :health 75}] Now we are going to redefine the buffy-destroy-all-vampires function to use the reset! function to update its value. We also need to convert the result to a vector before calling reset! Also note that we need to deference the vampire-line value when call using map.\n(defn buffy-destroy-all-vampires [] (reset! vampire-line (vec (map buffy-kill-vampire @vampire-line)))) Now let\u0026rsquo;s see what happens when Buffy kills them\n@vampire-line [#:user.Vampire{:name \u0026quot;Stu\u0026quot;, :health 0} #:user.Vampire{:name \u0026quot;Vance\u0026quot;, :health 0} #:user.Vampire{:name \u0026quot;Izzy\u0026quot;, :health 0}] (buffy-destroy-all-vampires) [#:user.Vampire{:name \u0026quot;Stu\u0026quot;, :health 0} #:user.Vampire{:name \u0026quot;Vance\u0026quot;, :health 0} #:user.Vampire{:name \u0026quot;Izzy\u0026quot;, :health 0}] @vampire-line [#:user.Vampire{:name \u0026quot;Stu\u0026quot;, :health 0} #:user.Vampire{:name \u0026quot;Vance\u0026quot;, :health 0} #:user.Vampire{:name \u0026quot;Izzy\u0026quot;, :health 0}] The vampires are finally dead and staying dead! Score one for the good guys!\n","permalink":"https://gigasquidsoftware.com/blog/2011/01/18/vampire-slaying-in-clojure-with-stm-part-2/","summary":"\u003cp\u003eIn Part 1, we used defrecords to create a vampire slayer named “Buffy” and a few vampires for her to kick around.  Today we are going to use Buffy and her vampires to explore STM (Software Transactional Memory) in Clojure for managing state.\u003c/p\u003e\n\u003cp\u003eRecap\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e(defrecord Vampire [name, health])\n(def vampire1 (Vampire. \u0026quot;Stu\u0026quot; 50))\n(def vampire2 (Vampire. \u0026quot;Vance\u0026quot; 100))\n(def vampire3 (Vampire. \u0026quot;Izzy\u0026quot; 75))\n\n(defrecord Slayer [name, weapon])\n(def kungfu 25)\n(def buffy (Slayer. \u0026quot;Buffy\u0026quot; kungfu))\n\n(defn hit [vampire, hitpoints]\n  (- (:health vampire) hitpoints))\n\n;vampires don't fight back but it takes time to kill them\n(def combat-time 20)\n\n(defn hit-vampire [vampire, slayer]\n  (Thread/sleep (* combat-time 10))\n  (assoc vampire :health (hit vampire (:weapon slayer))))\n\n(defn kill-vampire [vampire, slayer]\n  (if (\u0026gt; (:health vampire) 1)\n    (recur (hit-vampire vampire slayer) slayer)\n    (assoc vampire :health 0)))\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003eLet\u0026rsquo;s take our vampires and stand them up in a line for Buffy to fight.  We are also going to create a function that just has Buffy killing a vampire, rather then a generic slayer.\u003c/p\u003e","title":"Vampire Slaying in Clojure with STM - Part 2"},{"content":"It\u0026rsquo;s time to learn more Clojure. This time, Buffy the Vampire Slayer* is going to help us.\nFirst things first, of course we need vampires!\nLet\u0026rsquo;s create a vampire data type with defrecord. Our vampires are going to have two attributes, their name and the number of health points that they have. This is of course, how Buffy is going to slay them. If a vampire\u0026rsquo;s health points goes to zero, then they are dead. Well, they already are undead\u0026hellip; so let\u0026rsquo;s say they are slayed at that point and turn into dust.\nOur first vampire\u0026rsquo;s name is Stu and he has a health of 50.\n(defrecord Vampire [name, health]) (def vampire1 (Vampire. \u0026quot;Stu\u0026quot; 50)) When we type in the vampire1 value into the REPL we can see its values in a map format\nvampire1 #:user.Vampire{:name \u0026quot;Stu\u0026quot;, :health 50} Now we can access vampire1\u0026rsquo;s name by using the keys defined in the defrecord. Let\u0026rsquo;s get his name.\n(:name vampire1) \u0026quot;Stu\u0026quot; And his health\n(:health vampire1) 50 Lovely. But we are going to need more than one vampire for Buffy to fight. Let\u0026rsquo;s create some more.\n(def vampire1 (Vampire. \u0026quot;Stu\u0026quot; 50)) (def vampire2 (Vampire. \u0026quot;Vance\u0026quot; 100)) (def vampire3 (Vampire. \u0026quot;Izzy\u0026quot; 75)) Alright. Our evil doers are ready for a fight. Where is our hero? We need to create a slayer structure using defrecord like before. Our vampire slayer is going to have a name and a weapon that is worth a certain number of hit points. Buffy is such a hard case that she is just going to use her bare hands. We\u0026rsquo;ll define her kungfu to be worth 25 hit points.\n(defrecord Slayer [name, weapon]) (def kungfu 25) (def buffy (Slayer. \u0026quot;Buffy\u0026quot; kungfu)) Let\u0026rsquo;s check to make sure Buffy is ready to go\n(:name buffy) \u0026quot;Buffy\u0026quot; (:weapon buffy) 25 We have our main characters. Now we need a way for Buffy to hit the vampires. A simple function will do. We define a function that takes the vampire and the number of hitpoints and subtracts it from the vampire\u0026rsquo;s health. This gives us the new health of the vampire\n(defn hit [vampire, hitpoints] (- (:health vampire) hitpoints)) (hit vampire1 20) 30 Now let\u0026rsquo;s take that one step further and create another function that allows the slayer to hit the vampire with his/her weapon. We use out hit function and pass it the weapon of the slayer. Then we change the value of the vampire\u0026rsquo;s health to the new value with assoc. The function returns a new vampire structure with the new decremented health.\n(defn hit-vampire [vampire, slayer] (assoc vampire :health (hit vampire (:weapon slayer)))) (hit-vampire vampire1 buffy) #:user.Vampire{:name \u0026quot;Stu\u0026quot;, :health 25} Our vampires are totally lame, they don\u0026rsquo;t fight back, (at least in this code example), but it does take time for Buffy to kill them. Let\u0026rsquo;s define a time that it take for her to hit a vampire.\n(def combat-time 20) We\u0026rsquo;ll go back and redefine the hit-vampire function to include a sleep\n(defn hit-vampire [vampire, slayer] (Thread/sleep (* combat-time 10)) (assoc vampire :health (hit vampire (:weapon slayer)))) Now we can see how much time it takes Buffy to hit vampire1\n(time (hit-vampire vampire1 buffy)) \u0026quot;Elapsed time: 200.454173 msecs\u0026quot; #:user.Vampire{:name \u0026quot;Stu\u0026quot;, :health 25} This is nice, but we really want a way to define a function to recursively have the slayer keep hitting the vampire until it is dead. If the health of the vampire is less than 1, then then we will set the vampire\u0026rsquo;s health to 0 and return the vampire. Note that we use recur in the function to denote the recursive call.\n(defn kill-vampire [vampire, slayer] (if (\u0026gt; (:health vampire) 1) (recur (hit-vampire vampire slayer) slayer) (assoc vampire :health 0))) Testing it out with Buffy killing Stu the vampire1\n(kill-vampire vampire1 buffy) #:user.Vampire{:name \u0026quot;Stu\u0026quot;, :health 0} How long does it take Buffy to kill Stu? Not long.\n(time (kill-vampire vampire1 buffy)) \u0026quot;Elapsed time: 400.542595 msecs\u0026quot; #:user.Vampire{:name \u0026quot;Stu\u0026quot;, :health 0} What about a tougher vampire like vampire2?\nvampire2 #:user.Vampire{:name \u0026quot;Vance\u0026quot;, :health 100} (time (kill-vampire vampire2 buffy)) \u0026quot;Elapsed time: 801.318529 msecs\u0026quot; #:user.Vampire{:name \u0026quot;Vance\u0026quot;, :health 0} For fun, let\u0026rsquo;s redefine Buffy and give her some Holy Water as a weapon and see what happens.\n(def holy-water 100) (def buffy (Slayer. \u0026quot;Buffy\u0026quot; holy-water)) (time (kill-vampire vampire2 buffy)) \u0026quot;Elapsed time: 200.247375 msecs\u0026quot; #:user.Vampire{:name \u0026quot;Vance\u0026quot;, :health 0} So there you have it. We have explored defrecord and created some vampires for the express purpose of hitting. Not a bad way to blow off steam at the end of the day.\nStay tuned for part 2, where Buffy will line up the vampires and kill them using Clojure\u0026rsquo;s STM (Software Transaction Memory System) so they stay dead (or undead).\nIf you are a lawyer and object to Buffy the Vampire Slayer appearing in an code snippets as a Clojure var, please contact me and I will change the name to Biffy or Tiffy. Lego Vampire: http://www.flickr.com/photos/pasukaru76/4274684369\n","permalink":"https://gigasquidsoftware.com/blog/2011/01/12/vampire-slaying-with-clojure-part-1-defrecord/","summary":"\u003cp\u003eIt\u0026rsquo;s time to learn more Clojure.  This time, Buffy the Vampire Slayer* is going to help us.\u003c/p\u003e\n\u003cp\u003eFirst things first, of course we need vampires!\u003c/p\u003e\n\u003cp\u003eLet\u0026rsquo;s create a vampire data type with defrecord.  Our vampires are going to have two attributes, their name and the number of health points that they have.  This is of course, how Buffy is going to slay them.  If a vampire\u0026rsquo;s health points goes to zero, then they are dead.  Well, they already are undead\u0026hellip; so let\u0026rsquo;s say they are slayed at that point and turn into dust.\u003c/p\u003e","title":"Vampire Slaying with Clojure  - Part 1 defrecord"},{"content":"It\u0026rsquo;s late at night. The kids are all tucked snuggly in their beds and I am ready to explore mutual recursion on my own in Clojure after doing some reading of Programming Clojure. What better subject to explore them with then zombies? In this example we have two zombies – zombie1 and zombie2. Let\u0026rsquo;s represent each zombie as a sequence:\n(def zombie1 '(\u0026quot;z1_head\u0026quot;, \u0026quot;z1_r_arm\u0026quot; \u0026quot;z1_l_arm\u0026quot; \u0026quot;z1_torso\u0026quot; \u0026quot;z1_r_leg\u0026quot; \u0026quot;z1_l_leg\u0026quot;)) (def zombie2 '(\u0026quot;z2_head\u0026quot;, \u0026quot;z2_r_arm\u0026quot; \u0026quot;z2_l_arm\u0026quot; \u0026quot;z2_torso\u0026quot; \u0026quot;z2_r_leg\u0026quot; \u0026quot;z2_l_leg\u0026quot;)) zombie1 is ready to take a bite of zombie2\u0026rsquo;s left leg, since it is nice and tasty there at the end. Once zombie1 takes a bite, the body part will be added to its own sequence – but in the second position, so that the head is always first and ready to take another bite. So, if zombie2 just stood still and let itself be eaten, after one bite, zombie1 would look like this\n(z1_head, z2_l_leg, z1_r_arm, z1_l_arm, z1_torso, z1_r_leg, z1_l_leg)\nBut zombie2 is not just going to sit around and let itself be eaten, it is hungry too! So it looks at zombie1\u0026rsquo;s left leg hanging off there at the end and takes a bite whenever zombie1 takes a bite.\nLet\u0026rsquo;s define the functions. Because they will be mutually recursive and call each, we need to declare the vars first:\n(declare zombie1_eats zombie2_eats) Now let\u0026rsquo;s define the zombie functions. The zombie1_eats function will take 3 arguments, the first is the list that represents the eater (zombie1), the next is the list that represents the food (zombie2), and the last is the number of bites that zombie1 takes. The function will return the list that represents zombie1.\n(defn zombie1_eats [eater,food,bites] (if (= 0 bites) eater (if (= 0 (count food)) eater (zombie2_eats (drop-last food) (cons (first eater) (cons (last food) (rest eater)) ) bites)))) (defn zombie2_eats [eater, food bites] (if (= 0 bites) eater (if (= 0 (count food)) eater (zombie1_eats (drop-last food) (cons (first eater) (cons (last food) (rest eater)) ) (dec bites))))) After 0 bites:\nuser=\u0026gt; (zombie1_eats zombie1 zombie2 0) (\u0026quot;z1_head\u0026quot; \u0026quot;z1_r_arm\u0026quot; \u0026quot;z1_l_arm\u0026quot; \u0026quot;z1_torso\u0026quot; \u0026quot;z1_r_leg\u0026quot; \u0026quot;z1_l_leg\u0026quot;) After 1 bite\nuser=\u0026gt; (zombie1_eats zombie1 zombie2 1) (\u0026quot;z1_head\u0026quot; \u0026quot;z2_l_leg\u0026quot; \u0026quot;z1_r_arm\u0026quot; \u0026quot;z1_l_arm\u0026quot; \u0026quot;z1_torso\u0026quot; \u0026quot;z1_r_leg\u0026quot;) After 7 bites\n(user=\u0026gt; (zombie1_eats zombie1 zombie2 7) (\u0026quot;z1_head\u0026quot; \u0026quot;z1_r_leg\u0026quot; \u0026quot;z1_l_leg\u0026quot; \u0026quot;z2_r_arm\u0026quot; \u0026quot;z2_l_arm\u0026quot; \u0026quot;z2_torso\u0026quot;) After 1007 bites\nuser=\u0026gt; (zombie1_eats zombie1 zombie2 1007) (\u0026quot;z1_head\u0026quot; \u0026quot;z1_r_leg\u0026quot; \u0026quot;z1_l_leg\u0026quot; \u0026quot;z2_r_arm\u0026quot; \u0026quot;z2_l_arm\u0026quot; \u0026quot;z2_torso\u0026quot;) After 5000 bites\nuser=\u0026gt; (zombie1_eats zombie1 zombie2 5000) java.lang.StackOverflowError (NO_SOURCE_FILE:0) Whoops we blew the stack! Don\u0026rsquo;t worry – put those zombies on a trampoline!\nClojure provides a function for optimizing mutual recursion. The only thing that we need to do is to modify our zombie functions with a “#” to introduce an anonymous function. Our new zombie methods are:\n(defn zombie1_eats [eater,food,bites] (if (= 0 bites) eater (if (= 0 (count food)) eater #(zombie2_eats (drop-last food) (cons (first eater) (cons (last food) (rest eater)) ) bites)))) (defn zombie2_eats [eater, food bites] (if (= 0 bites) eater (if (= 0 (count food)) eater #(zombie1_eats (drop-last food) (cons (first eater) (cons (last food) (rest eater)) ) (dec bites))))) Now lets try again:\nuser=\u0026gt; (trampoline zombie1_eats zombie1 zombie2 5000) (\u0026quot;z1_head\u0026quot; \u0026quot;z1_r_arm\u0026quot; \u0026quot;z1_l_arm\u0026quot; \u0026quot;z1_torso\u0026quot; \u0026quot;z1_r_leg\u0026quot; \u0026quot;z1_l_leg\u0026quot;) No problem. Even bigger\u0026hellip;\n(trampoline zombie1_eats zombie1 zombie2 50004) (\u0026quot;z1_head\u0026quot; \u0026quot;z2_l_arm\u0026quot; \u0026quot;z2_torso\u0026quot; \u0026quot;z2_r_leg\u0026quot; \u0026quot;z2_l_leg\u0026quot; \u0026quot;z1_r_arm\u0026quot;) There are other techniques to solve this as well in Clojure. In Stuart Holloway\u0026rsquo;s book, he mentions converting to self-recursion, replacing recursion with laziness and shortcutting recursion with memoization.\nBut for me, there is nothing more enjoyable than putting those zombies on a trampoline!\n","permalink":"https://gigasquidsoftware.com/blog/2010/12/08/mutually-recursive-zombies-on-a-trampoline/","summary":"\u003cp\u003eIt\u0026rsquo;s late at night.  The kids are all tucked snuggly in their beds and I am ready to explore mutual recursion on my own in Clojure after doing some reading of \u003ca href=\"http://pragprog.com/titles/shcloj/programming-clojure\"\u003eProgramming Clojure\u003c/a\u003e.  What better subject to explore them with then zombies?  In this example we have two zombies – zombie1 and zombie2.   Let\u0026rsquo;s represent each zombie as a sequence:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e(def zombie1 '(\u0026quot;z1_head\u0026quot;, \u0026quot;z1_r_arm\u0026quot; \u0026quot;z1_l_arm\u0026quot; \u0026quot;z1_torso\u0026quot; \u0026quot;z1_r_leg\u0026quot; \u0026quot;z1_l_leg\u0026quot;))\n\n(def zombie2 '(\u0026quot;z2_head\u0026quot;, \u0026quot;z2_r_arm\u0026quot; \u0026quot;z2_l_arm\u0026quot; \u0026quot;z2_torso\u0026quot; \u0026quot;z2_r_leg\u0026quot; \u0026quot;z2_l_leg\u0026quot;))\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003ezombie1 is ready to take a bite of zombie2\u0026rsquo;s left leg, since it is nice and tasty there at the end.  Once zombie1 takes a bite, the body part will be added to its own sequence – but in the second position, so that the head is always first and ready to take another bite.  So, if zombie2 just stood still and let itself be eaten, after one bite, zombie1 would look like this\u003c/p\u003e","title":"Mutually Recursive Zombies on a Trampoline"},{"content":"What do Zen and Zombies have in common? You probably got the beginning with the letter “Z”, but did you also guess Ruby? This blog post is to share two awesome and fun filled ways to learn Ruby and Ruby and Rails.\nFirst, let\u0026rsquo;s start with the Zen. Edgecase created a great way of learning Ruby. It is through Ruby Koans . Koans are a way of teaching Zen through questions. The master asks the student a question. The student then meditates on it until they come to the answer , eventually leading to enlightenment. The Ruby Koans are cleverly designed to teach bite size tidbits of the Ruby language through the completion of unfinished test cases. Each test case is a Koan. Every time you fix the test case by filling in the blanks, you are gaining a deeper understanding of the language. The main path_to_enlightment.rb file leads you through test cases that explore many areas of the languages such as Strings, Classes, Methods, and Exceptions. Enlightenment has never been so much fun.\nMoving from enlightenment to tasty brains for Zombies, we have Rails for Zombies http://railsforzombies.org. Envy Labs has raised the bar in online tutorials. The traditional way to learn Ruby on Rails is to download the programs, struggle a bit as you figure out how to install it and then work through exercises locally through a book, website guide or podcast. Rails for Zombies takes out all the pain of the traditional way and replaces it with enjoyment. Everything is done in the browser, including code. The format is to watch a video with Zombies and Rails code and then take what you learned by completing a lab exercise in the browser. After you complete the lab, you unlock the next video. Over the course of five labs, you create a Twitter web app for the Zombie hoard. It\u0026rsquo;s a win for you and the Zombies.\nSo if you are curious about Ruby, these are two great ways to try it out. I promise you that will have fun learning. Although, some people may also experience occasional uncontrollable desire to eat brains\u0026hellip;.\nPhoto Credits\n_Zen: _http://www.flickr.com/photos/shebalso/121744939/\nZombie: http://www.flickr.com/photos/70109407@N00/5188908499/\n","permalink":"https://gigasquidsoftware.com/blog/2010/11/20/zen-and-zombies-adventures-in-ruby/","summary":"\u003cp\u003eWhat do Zen and Zombies have in common?  You probably got the beginning with the letter “Z”, but did you also guess Ruby?  This blog post is to share two awesome and fun filled ways to learn Ruby and Ruby and Rails.\u003c/p\u003e\n\u003cp\u003eFirst, let\u0026rsquo;s start with the Zen.  \u003ca href=\"http://edgecase.com/\"\u003eEdgecase \u003c/a\u003ecreated a great way of learning Ruby.  It is through \u003ca href=\"http://rubykoans.com/\"\u003eRuby Koans \u003c/a\u003e.   Koans are a way of teaching Zen through questions.  The master asks the student a question.  The student then meditates on it until they come to the answer , eventually leading to enlightenment.  The Ruby Koans are cleverly designed to teach bite size tidbits of the Ruby language through the completion of unfinished test cases.  Each test case is a Koan.  Every time you fix the test case by filling in the blanks, you are gaining a deeper understanding of the language.  The main path_to_enlightment.rb file leads you through test cases that explore many areas of the languages such as Strings, Classes, Methods, and Exceptions.  Enlightenment has never been so much fun.\u003c/p\u003e","title":"Zen and Zombies - Adventures in Ruby"},{"content":"There was a question today on Twitter about how to go about finding the word with the most consecutive consonants in the dictionary file. Of course, being a typical developer, when presented with a problem – I am usually not satisfied until I find a solution. Since I am interested in learning Clojure, I thought I would try to solve this problem functionally.\nArmed with Stuart Halloway\u0026rsquo;s “Programming Clojure” and trusty Google by my side, I embarked on my first Clojure mission.\nStarting small – I decided to tackle the issue of finding consecutive consonants in a word. I found that re-seq handles regex very nicely\nuser=\u0026gt; (re-seq #\u0026quot;[^aeiou]{2,}\u0026quot; \u0026quot;batty\u0026quot;) (\u0026quot;tty\u0026quot;) Building on … let\u0026rsquo;s find the number of letters in this word. Since we have a sequence – we need to get the first element off of it, convert it to a string and find the length of it\nuser=\u0026gt; (.length (str (first (re-seq #\u0026quot;[^aeiou]{2,}\u0026quot; \u0026quot;batty\u0026quot;)))) 3 Not bad – but let\u0026rsquo;s turn this into a function now\nuser=\u0026gt; (defn count-cons [s] (.length (str (first (re-seq #\u0026quot;[^aeiou]{2,}\u0026quot; s)))) ) #'user/count-cons Now we can call the function directly\nuser=\u0026gt; (count-cons \u0026quot;batty\u0026quot;) 3 Alright – we are making progress. Next step, we need to be able to compare two words and see which has the bigger consonant count and return that. For this, we will need a little “if” magic.\nuser=\u0026gt; (defn compare-words [s1,s2] (if (\u0026gt; (count-cons s1) (count-cons s2)) s1 s2)) #'user/compare-words Let\u0026rsquo;s test it out\n#'user/compare-words user=\u0026gt; (compare-words \u0026quot;batty\u0026quot; \u0026quot;bat\u0026quot;) \u0026quot;batty\u0026quot; user=\u0026gt; (compare-words \u0026quot;bat\u0026quot; \u0026quot;batty\u0026quot;) \u0026quot;batty\u0026quot; Oh, yes, we are getting to the good part now. Since we have a function that we can call on two arguments and give us one back that we can work with – we are ready to pull out the big guns …. reduce!\nuser=\u0026gt; (reduce compare-words [\u0026quot;vat\u0026quot;, \u0026quot;batty\u0026quot;, \u0026quot;cars\u0026quot;]) \u0026quot;batty\u0026quot; Yeah! Next we just need to feed it a file. For this, after doing some research, I used the duck-streams library – you need to load it in using\nuser=\u0026gt; (use '[clojure.contrib.duck-streams :only (spit read-lines)]) nil We open the file and read the lines and feed it to our function\nuser=\u0026gt; (reduce compare-words (read-lines \u0026quot;/usr/share/dict/words\u0026quot;)) \u0026quot;Ångström\u0026quot; Yes, my regex needs some tweaking - but for this exercise, I am content.\nWhen you just have the working code. It is actually quite concise:\n;Counting consecutive consonants (use '[clojure.contrib.duck-streams :only (spit read-lines)]) (defn count-cons [s] (.length (str (first (re-seq #\u0026quot;[^aeiou]{2,}\u0026quot; s)))) ) (defn compare-words [s1,s2] (if (\u0026gt; (count-cons s1) (count-cons s2)) s1 s2)) (reduce compare-words (read-lines \u0026quot;/usr/share/dict/words\u0026quot;)) All in all, a fun evening trying to think functionally.\n","permalink":"https://gigasquidsoftware.com/blog/2010/10/12/clojure-dictionary-challenge/","summary":"\u003cp\u003eThere was a question today on Twitter about how to go about finding the word with the most consecutive consonants in the dictionary file.  Of course, being a typical developer, when presented with a problem – I am usually not satisfied until I find a solution.  Since I am interested in learning Clojure, I thought I would try to solve this problem functionally.\u003c/p\u003e\n\u003cp\u003eArmed with Stuart Halloway\u0026rsquo;s “Programming Clojure” and trusty Google by my side, I embarked on my first Clojure mission.\u003c/p\u003e","title":"Clojure Dictionary Challenge"},{"content":" _Photo by Valentin Baranovsky - Uliana Lopatkina and Danila Korsuntsev. _\nMany moons ago, I spent a couple of years dancing with a ballet company. You wouldn\u0026rsquo;t think that much of that experience would transfer to development projects, but I give you an example in partnership, the can be applicable straight from the ballet world to the software world. The partnership in question is the one between the lead ballerina and the lead male dancer called a “pas de deux.” In many ballets, this dance involves the ballerina being a swan/princess and the male dancer being a prince/sorcerer. But in my example, it really doesn\u0026rsquo;t matter that much. The only important point is that they are the best dancers in the whole company.\nEach one of them can astound the audience in their solo moves, but in their duets – they can do really awesome things. The male dancer supports the ballerina during dazzling spins and carries and lifts her in heart-stopping moves across the stage. When it is done well, the audience goes crazy and gives them a standing ovation. They can only pull off this spectacular performance if they have developed a great partnership. Of course they are brilliant performers individually. But they need more than that to pull of a pas de deux. The job of the ballerina is to be lovely, graceful and technically brilliant. The male partner must also to graceful and skillful (maybe not so lovely) – but his main job – is to make the ballerina look good. Failure to make the ballerina look good – even if you are the most talented dancer in the entire universe – will still make you a lousy partner. I don\u0026rsquo;t care if he can spin one hundred times a second and can jump one hundred feet in the air. If he is performing a pas de deux, and he drops his lovely ballerina on the floor, he is a lousy partner and she will be guaranteed to burn her toe shoes before agreeing to share the stage with him.\nReasons for being a bad partner in ballet (or dropping your ballerina):\nYou didn\u0026rsquo;t have enough time to rehearse\nYou don\u0026rsquo;t like your ballerina\nYou think you should be a the star of the show and don\u0026rsquo;t want anyone to look better than you.\nNow let\u0026rsquo;s go to the world of the corporate software project. You have your developers and your business partner – the customer. You, the developers, have the supporting role. You main job is to make the customer look good. That\u0026rsquo;s right, through your mastery of technology, you must partner with your customer to help them accomplish their business goals and make them look great. If you metaphorically, drop your customer on the floor, then you are obviously not a good partner.\nReasons for being a bad developer partner in software projects:\nYou are new to the team and haven\u0026rsquo;t gotten into the communication groove yet This is alright in the beginning of a project. Heck, it happens when ballet dancers are just learning their dances too. If you are doing short iteration cycles, then the first couple will be a little rough. But with feedback you will improve and your team will start to gel and shift into high performance.\nYou think all people that are not IT are idiots. I have seen this sentiment common on projects that have a strict division between the IT people and the business people. Somehow, it turns into a horrible sentiment that the anything that the business users ask for is a waste of time and only the IT department knows the right things to do. If you have your team mixed with developers and business people this will help break down such harmful barriers.\nYou think that you are a Superstar and want to showcase your technical talents in your application – maybe they will start asking you to speak at the Google Confs after they see your work. You may be the Ninja Assassin of the Black Arts of Java, Ruby and all the cool Functional languages, but if you can\u0026rsquo;t accomplish what your business needs to look good, then you suck as a partner. Frequent communication with the customer is key. Fun is fine, but please examine your motivations for putting in that cool new feature. Is it going to make the customer look good or you? Again, short iterations and feedback cycles will help put the focus back on what the customer wants and needs.\nCommunication, feedback are essential elements to a good partnership in the ballet world and the software development world. Don\u0026rsquo;t ever forget to make your customer look good and your projects will be sure to get a standing ovation.\n","permalink":"https://gigasquidsoftware.com/blog/2010/09/13/agile-software-lessons-from-ballet/","summary":"\u003cp\u003e\u003cimg alt=\"Swan Lake\" loading=\"lazy\" src=\"/images/posts/cae5d4d5-kirov-swan-lopatkina.jpg\"\u003e\n_Photo by Valentin Baranovsky - Uliana Lopatkina and Danila Korsuntsev. _\u003c/p\u003e\n\u003cp\u003eMany moons ago, I spent a couple of years dancing with a ballet company.  You wouldn\u0026rsquo;t think that much of that experience would transfer to development projects, but I give you an example in partnership, the can be applicable straight from the ballet world to the software world.  The partnership in question is the one between the lead ballerina and the lead male dancer called a “pas de deux.”  In many ballets, this dance involves the ballerina being a swan/princess and the male dancer being a prince/sorcerer.  But in my example, it really doesn\u0026rsquo;t matter that much.  The only important point is that they are the best dancers in the whole company.\u003c/p\u003e","title":"Agile Software Lessons from Ballet"},{"content":"If you are trying to run ruby rvm and rails 3.0 on Ubuntu you might run into this problem when you start up you server.\nLoadError: no such file to load -- openssl After much googling and researching – just installing the openssl library on your system won\u0026rsquo;t fix the problem. You need to recompile and install your rvm ruby version with the openssl. I found this fixed it for me.\nrvm install 1.9.2-p0 -C --with-openssl-dir=$rvm_path/usr There is also another solution here so you don\u0026rsquo;t have to recompile every time\n","permalink":"https://gigasquidsoftware.com/blog/2010/09/12/openssl-fix-for-rails-3.0-on-ubuntu/","summary":"\u003cp\u003eIf you are trying to run ruby rvm and rails 3.0 on Ubuntu you might run into this problem when you start up you server.\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003eLoadError: no such file to load\n-- openssl\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003eAfter much googling and researching – just installing the openssl library on your system won\u0026rsquo;t fix the problem.  You need to recompile and install your rvm ruby version with the openssl.  I found this fixed it for me.\u003c/p\u003e","title":"Openssl fix for Rails 3.0 on Ubuntu"},{"content":"In honor of the Ruby Why Day, I was inspired to dabble in Ruby Blocks after being reading \u0026ldquo;Fox In Socks\u0026rdquo; multiple times to my children before bed. For all of you parents out there that have read the book many, many times while your children are giggling at your pronunciation difficulties, I am sure this bit will be familiar:\ndef fox_in_socks_blocks chicks_bricks = [\u0026quot;Chicks\u0026quot;,\u0026quot;bricks\u0026quot;,\u0026quot;blocks\u0026quot;,\u0026quot;clocks\u0026quot;] yield chicks_bricks[0..1] yield [chicks_bricks[0],chicks_bricks[2]] yield chicks_bricks end fox_in_socks_blocks do |sillywords| puts \u0026quot;#{sillywords[0]} with #{sillywords[1]} come.\u0026quot; if sillywords.size \u0026lt; 3 puts \u0026quot;#{sillywords[0]} with #{sillywords[1]} and #{sillywords[2]} and #{sillywords[3]} come.\u0026quot; if sillywords.size \u0026gt;= 3 end That\u0026rsquo;s right - the output is: Chicks with bricks come. Chicks with blocks come. Chicks with bricks and blocks and clocks come.\nIs your tongue numb?\nHappy Why Day!\n","permalink":"https://gigasquidsoftware.com/blog/2010/08/20/fox-in-socks-blocks/","summary":"\u003cp\u003eIn honor of the Ruby \u003ca href=\"http://www.globalnerdy.com/2010/08/19/whyday-today-august-19th/\"\u003eWhy Day\u003c/a\u003e, I was inspired to dabble in Ruby Blocks after being reading \u0026ldquo;Fox In Socks\u0026rdquo; multiple times to my children before bed.  For all of you parents out there that have read the book many, many times while your children are giggling at your pronunciation difficulties, I am sure this bit will be familiar:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003edef fox_in_socks_blocks\n  chicks_bricks = [\u0026quot;Chicks\u0026quot;,\u0026quot;bricks\u0026quot;,\u0026quot;blocks\u0026quot;,\u0026quot;clocks\u0026quot;]\n  yield chicks_bricks[0..1]\n  yield [chicks_bricks[0],chicks_bricks[2]]\n  yield chicks_bricks\nend\n\nfox_in_socks_blocks do |sillywords|\n  puts \u0026quot;#{sillywords[0]} with #{sillywords[1]} come.\u0026quot; if sillywords.size \u0026lt; 3\n  puts \u0026quot;#{sillywords[0]} with #{sillywords[1]} and #{sillywords[2]} and #{sillywords[3]} come.\u0026quot; if sillywords.size \u0026gt;= 3\nend\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003eThat\u0026rsquo;s right - the output is:\n\u003ccode\u003eChicks with bricks come. Chicks with blocks come. Chicks with bricks and blocks and clocks come.\u003c/code\u003e\u003c/p\u003e","title":"Fox In Socks Blocks"},{"content":"I am cruising along in my morning. I have a cup of tea in my hand and a good outlook on my tasks at hand. The code is flowing off of my fingertips. I am feeling pretty smart. Then the cloud moves in and the code darkens. I am at a roadblock. I try to google, I try debugging, I try calling in my fellow developers to see if they can see what the problem is\u0026hellip; no luck. I bang my head unproductively for another hour and then go home. A fresh start in the morning and a fresh cup of day move me in a new direction, somehow I stumble upon the answer and quite frankly, it was so simple I can\u0026rsquo;t believe I missed it. I feel not so smart. This is one of the many smart-not-so-smart waves that rule the life of a developer.\nThe example above is what I would call a mini-smart-not-so-smart wave. There are much bigger ones too and much more important too. These are the sort of moments that you encounter that you feel stupid in a really good way. You learn a totally new approach or way of doing things and much better because of it. One of these moments was when I went up to a MySQL Drunken Query Master Presentation by Jay Pipes. He is a brilliant speaker. Before I went up there, I thought I was pretty smart. I knew how to swing inner and outer joins on my queries and how to optimize using the explain plan\u0026hellip;. After listening to him, I felt really not so smart. I had been using Theta style instead of Ansi style in my queries and I really had no idea of how to use the storage engines properly and really understand how the optimizer worked or even more important\u0026hellip; to really do queries well, you need to stop thinking in logic loops (the comfortable world of the developer) and start thinking in sets. Yes, I felt really dim, but my world view had grown and I had found a whole range of stuff that I didn\u0026rsquo;t know. I had uncovered a whole dark section “how do you know what you don\u0026rsquo;t know”.\nI had similar experiences when I attended some OWASP security talks and realized that I really didn\u0026rsquo;t know much about software security and it is actually quite important to learn and consider in design and development to make better more robust software. More recently, I have been spending my not-so-smart cycle time learning more about Test-Driven Design and Agile development by learning Ruby and attending some awesome local community user groups.\nSo, if you are feeling smart and have been for awhile. It is really time to look around for something to challenge you views. Look at a completely different field in technology then you are used to, try QA, project management, security, cloud computing, data governance. Go out in the community and talk to people in user groups. Push yourself of in the not-so-smart wave section and you will emerge smarter and happier for it.\n","permalink":"https://gigasquidsoftware.com/blog/2010/08/18/the-smart-not-so-smart-wave-function/","summary":"\u003cp\u003eI am cruising along in my morning.  I have a cup of tea in my hand and a good outlook on my tasks at hand.  The code is flowing off of my fingertips.  I am feeling pretty smart.  Then the cloud moves in and the code darkens.  I am at a roadblock.   I try to google, I try debugging, I try calling in my fellow developers to see if they can see what the problem is\u0026hellip; no luck.  I bang my head unproductively for another hour and then go home.  A fresh start in the morning and a fresh cup of day move me in a new direction, somehow I stumble upon the answer and quite frankly, it was so simple I can\u0026rsquo;t believe I missed it.  I feel not so smart.   This is one of the many smart-not-so-smart waves that rule the life of a developer.\u003c/p\u003e","title":"The Smart Not-So-Smart Wave Function"},{"content":"I have always wanted to contribute to Open Source. I have reaped the benefits of using Open Source packages throughout the years, I sincerely want to give back. What has been stopping me all this time? Lack of time is my main excuse. I have two small children and by the time I clean up from dinner and get them bathed and off to bed, there is little time left to code. I tend to use this excuse for lots of other tasks that I avoid around the house, like closet cleaning, reorganizing the garage, etc … But an excuse is exactly what it is.\nI learned an invaluable technique to tackling projects around the house that I would like to get done, but seem too large or for some other reason have become subject to procrastination. First, I schedule a day to do something about it and then I put on a timer and just start doing it for 15 minutes. After 15 minutes, I am officially done. I can quit with no guilt and have the lovely feeling of having made a dent. Most often, once I get started, I want to keep with it and really get rolling. That\u0026rsquo;s OK too.\nLast Wednesday, I decided to apply this technique and made a date with Open Source. After a Ruby user group, the night before, demonstrated the mechanics of fixing a bug using GitHub, I was finally confident enough to give it a go myself. I created a GitHub account, forked the Redmine project, fixed a bite-sized bug and submitted a patch – all in one night!\nI was so jazzed up about it, that I decided that I was going to continue in my Open Source contribution quest on a limited time budget, by declaring that my Wednesday night is my Open Source night. It might only be 15 or 30 min, but I will be doing something and feeling that contribution buzz goodness.\nI encourage everyone that has been struggling to find time for Open Source to just schedule one night a week. Just do something for 15 min and see what flows …\n","permalink":"https://gigasquidsoftware.com/blog/2010/07/30/open-source-wednesdays/","summary":"\u003cp\u003eI have always wanted to contribute to Open Source.  I have reaped the benefits of using Open Source packages throughout the years, I sincerely want to give back.  What has been stopping me all this time?      Lack of time is my main excuse.  I have two small children and by the time I clean up from dinner and get them bathed and off to bed, there is little time left to code.   I tend to use this excuse for lots of other tasks that I avoid around the house, like closet cleaning, reorganizing the garage, etc …  But an excuse is exactly what it is.\u003c/p\u003e","title":"Open Source Wednesdays"},{"content":"I decided to start playing with RDFs to start me on the road to understanding and programming Semantic Web. As always, the first step it to start with a “Hello World” type of exercise. In my case, I had armed myself with a good cappuccino at Starbucks and decided to set myself with a purl link and FOAF page. FOAF (Friend of a Friend) is one of the most popular vocabularies out there for RDF (Resource Description Framework). It expresses relationships in a machine readable format and is considered one of the first social Semantic Web applications.\nWhen you look at a foaf.rdf file, it is basically just an file with xml tags:\n\u0026lt;foaf:Person rdf:ID=\u0026quot;me\u0026quot;\u0026gt; \u0026lt;foaf:name\u0026gt;Carin Meier\u0026lt;/foaf:name\u0026gt; \u0026lt;foaf:givenname\u0026gt;Carin\u0026lt;/foaf:givenname\u0026gt; \u0026lt;foaf:family_name\u0026gt;Meier\u0026lt;/foaf:family_name\u0026gt; \u0026lt;foaf:nick\u0026gt;squid\u0026lt;/foaf:nick\u0026gt; Not too much fun to start coding by hand though. Luckily, there is a handy dandy generator - FOAF-a-matic. Just fill in the form and you can easily generate the basic foaf rdf file for yourself. You can always add to it later. Save the file as foaf.rdf somewhere on your website for indexing.\nNow you can do some fun stuff with it. You can check and visualize your RDF document with http://www.w3.org/RDF/Validator/. Or you can use a FOAF visualizer.\nThe final part is to set yourself up with a purl address. Purl.org is a website that is dedicated to providing web endpoints or addresses that can be indentifiers for individuals. It provides a layer of indirection that is very useful in the changing world of the web. For example, if I use my work web page link as my identifier in my RDF and then I change jobs, all my FOAF links will be broken. However, I can use my purl address and set up my identifier as my webpage and then change it when then need arises. So logon to purl.org and set yourself up with an account. When other people \u0026ldquo;know\u0026rdquo; you in FOAF, they can use your purl link:\nfoaf:Person foaf:nameCarin Meier\u0026lt;/foaf:name\u0026gt; \u0026lt;rdfs:seeAlso rdf:resource=\u0026ldquo;http://purl.org/net/cmeier\u0026quot;/\u0026gt; \u0026lt;/foaf:Person\u0026gt;\nMy FOAF is http://gigasquidsoftware.com/foaf/foaf.rdf My purl link is http://purl.org/net/cmeier\nThat\u0026rsquo;s it! Hello World in FOAF!\n","permalink":"https://gigasquidsoftware.com/blog/2010/07/08/hello-world-in-rdf/","summary":"\u003cp\u003eI decided to start playing with RDFs to start me on the road to understanding and programming Semantic Web.  As always, the first step it to start with a “Hello World” type of exercise.  In my case, I had armed myself with a good cappuccino at Starbucks and decided to set myself with a purl link and FOAF page.\n\u003ca href=\"https://secure.wikimedia.org/wikipedia/en/wiki/FOAF_%28software%29\"\u003e\nFOAF (Friend of a Friend)\u003c/a\u003e is one of the most popular vocabularies out there for RDF (Resource Description Framework).  It expresses relationships in a machine readable format and is considered one of the first social Semantic Web applications.\u003c/p\u003e","title":"Hello World in RDF"},{"content":"I attended my first NFJS conference last weekend up in Columbus. Overall, it was an excellent experience. The speakers were all first rate and I got a chance to hang out and meet some other like-minded people who are interested in giving up a weekend to learn new technologies and generally just geek-out.\nThe main technologies that stood out to me are concurrency and semantic web. Concurrency and functional programming are becoming more and more important with the ability to scale out on the server, rather then scale up (horizontal vs vertical scaling). There is always some threshold to the amount of power that you can throw at one system. However, that limit disappears if you can spread the load out across many servers. Java runs into some real problems with threads and concurrency. For this reason, the functional languages like Scala, Erlang, and Clojure are really starting to shine. I was so impressed with Clojure, that I picked up a book for my “play around and take a look at” tech stack.\nThe highlight of the conference for me was on Sunday. I was fortunate enough to attend all of Brian Sletten\u0026rsquo;s sessions on REST, RDF, and all things Semantic Web. I was interested in the Semantic Web before I attended, but afterwards it is my new love. I have always been interested in databases and datasets, so discovering a technology that enriches data in a open distributed way across the web just made me giddy. The potential enterprise applications are very exciting. When RDF is combined with a HATEOS architecture, you have can have a robust, scalable, agile architecture that can integrate data across many different systems and datasources. These rich datasources can be sliced and diced for reporting and BI and can also be secured by row/ column level like security. On the e-commerce side of the Internet, even very simple implementations of RDF vocabularies are yielding very promising results. Best Buy put in a semantic web vocabulary on their website that resulted in 30% increase of sales. It is a very exciting time for semantic web technologies. I am a firm believer in that it is “ all about the data”. I think for the future it will be more like “Why have just data when you can have data with context?”\nAll in all, I had a great time and it was definitely worth the trip up to Columbus for the weekend. If you have chance to check out NFJS or any stuff about the Semantic Web or Functional Languages, go for it. You will enjoy it.\n","permalink":"https://gigasquidsoftware.com/blog/2010/07/01/no-fluff-just-stuff-columbus-2010/","summary":"\u003cp\u003eI attended my first NFJS conference last weekend up in Columbus.  Overall, it was an excellent experience.   The speakers were all first rate and I got a chance to hang out and meet some other like-minded people who are interested in giving up a weekend to learn new technologies and generally just geek-out.\u003c/p\u003e\n\u003cp\u003eThe main technologies that stood out to me are concurrency and semantic web.   Concurrency and functional programming are becoming more and more important with the ability to scale out on the server, rather then scale up (horizontal vs vertical scaling).    There is always some threshold to the amount of power that you can throw at one system.  However, that limit disappears if you can spread the load out across many servers.  Java runs into some real problems with threads and concurrency.  For this reason, the functional languages like Scala, Erlang, and Clojure are really starting to shine.   I was so impressed with Clojure, that I picked up a book for my “play around and take a look at” tech stack.\u003c/p\u003e","title":"No Fluff Just Stuff - Columbus 2010"},{"content":"\nI have been attending talks on functional programming languages at NFJS over the past couple of days. I have to admit it, I am really taken with the power of Scala and Clojure to tackle problems that Java cannot handle. I even purchased a Clojure book to add to my \u0026ldquo;languages to take a good hard look at\u0026rdquo; stack. I really believe that it is true that the functional languages have a lot to offer.\nHowever, let\u0026rsquo;s not loose track of one really powerful tool that the Object Oriented world provides to us. This is the way to model the world in a more natural way. Since we do this all the time in Java and other object oriented languages, we take it for granted now. But the advantage that this modeling the world in our mind and our code is tremendous. One of the biggest constraint on developing software is the ability to hold in our minds the mental model of what the code is doing and how it is doing it. Once, you do this – you “know the application”. Having the ability to break the world up into chunks that more easily fit allows us to more naturally build applications without the complexity drowning us out.\nI am wary of the temptation to “throw the baby out with the bathwater” to go to pure functional and leave objects behind. This is way Scala seems like a pragmatic solution, since it allows you to turn the dial back and forth from the Object Oriented way of doing things to the functional side.\nThat being said, I still intend to learn Clojure next instead of Scala. Why? Because to learn a new language that is a new way of thinking, I would prefer not to have an alternative way to fall back to old familiar ways of thinking. That way you can really get a new perspective on things to see what the true functional side has to offer. And no, I am not hard core enough to learn Haskell.\nOne thing is for sure. The future is multi-core.\n","permalink":"https://gigasquidsoftware.com/blog/2010/06/27/not-ready-to-throw-the-object-model-out-with-the-bath-water/","summary":"\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/images/posts/78e4b58f-9925947563_50031edb46_o.jpg\"\u003e\u003c/p\u003e\n\u003cp\u003eI have been attending talks on functional programming languages at NFJS over the past couple of days.  I have to admit it, I am really taken with the power of Scala and Clojure to tackle problems that Java cannot handle.  I even purchased a Clojure book to add to my \u0026ldquo;languages to take a good hard look at\u0026rdquo; stack.   I really believe that it is true that the functional languages have a lot to offer.\u003c/p\u003e","title":"Not ready to throw the Object Model out with the Bath Water"},{"content":"I think most developers are familiar with getting in the “zone”. The place you get when you are totally in focus and in the flow of development. The code comes quickly, the ideas are together and everything just seems to work. It is the sweet spot of productivity. I have found the best way for me to get into the zone is to put on my headphones, arrange some uninterrupted time and just start going.\nThere is another zone, however, that I think is just as important. This is getting into the zone with the customer. At the beginning of a project, or even just joining a new company, you have to get to know your customer. It involves a lot of learning the business rules, processes, and just plain communication style. In these early stages, there is a bound to be some misunderstandings. This is where the iterative development process really shines. With each feedback cycle, you get closer and closer to thinking and understanding what the customer and the business wants and needs. As your project development you can start be in such harmony that you can consistently develop what they need on the first try and even anticipate areas of improvement that will delight the business user. To me, to get into the development zone and the customer zone at the same time is the really sweet spot.\nWhat happens if you are just in you development zone and not in the customer zone? Well, cranking out beautiful code that the doesn\u0026rsquo;t serve the business needs is not beneficial. Your code can be the most beautiful and elegant ever produced, but if it doesn\u0026rsquo;t do it\u0026rsquo;s job, what use is it? What happens if you in the customer zone and have achieved a mind meld with your user and have internalized exactly what they need, but you get never get into your development groove. Let\u0026rsquo;s say for the sake of argument, you are constantly being interrupted and pulled into pointless meetings, so you can never concentrate long enough to get into the groove? The code doesn\u0026rsquo;t write itself. It remains unrealized and of course that business never realizes the value either.\nSo, I think, really you need to get in two zone simultaneously to be the most productive developer that you can be. Luckily, following an agile development process will get you there.\n","permalink":"https://gigasquidsoftware.com/blog/2010/06/09/customer-zone--developer-zone-most-excellent-zone/","summary":"\u003cp\u003eI think most developers are familiar with getting in the “zone”.  The place you get when you are totally in focus and in the flow of development.  The code comes quickly, the ideas are together and everything just seems to work.  It is the sweet spot of productivity.  I have found the best way for me to get into the zone is to put on my headphones, arrange some uninterrupted time and just start going.\u003c/p\u003e","title":"Customer Zone + Developer Zone = Most Excellent Zone"},{"content":"How many minutes and hours have been wasted trying to decide if a ticket is a feature or a bug? Yes, I have been there, entering a new item ticket, the dropdown in the tracker glares at me. Decide! Is is a bug or a feature. Some are clear-cut, of course. The ever popular null-pointer on unvalidated input for example. But others are not so clear. What about the field that you thought was supposed to viewable employees in the supervisor\u0026rsquo;s location, but really ended up needing to be viewable to the employee\u0026rsquo;s in the supervisor\u0026rsquo;s location and the direct reports in another location? The question then turns on whether or not this information was in the \u0026ldquo;spec\u0026rdquo; or whether the business user didn\u0026rsquo;t let the developer know about it. Now the question has created an ugly situation of \u0026ldquo;blame\u0026rdquo;. Whose fault is it?\nWhile I am all for development responsibility and testing, I think this line of thinking can only lead to trouble and harm the close relationship sought by the business user and the developer. How can you truly have agile, collaborative development, if the two parties are at odds, even in the small sense of categorizing work tickets. In the end, the same work needs to be done to get to the end result of having the application serve the business needs. So let\u0026rsquo;s lay off the blame game and just say no to bug vs feature.\n","permalink":"https://gigasquidsoftware.com/blog/2010/05/27/feature-vs-bug-does-it-matter/","summary":"\u003cp\u003eHow many minutes and hours have been wasted trying to decide if a ticket is a feature or a bug?  Yes, I have been there, entering a new item ticket, the dropdown in the tracker glares at me.  Decide!  Is is a bug or a feature.  Some are clear-cut, of course.  The ever popular null-pointer on unvalidated input for example.  But others are not so clear.   What about the field that you thought was supposed to viewable employees in the supervisor\u0026rsquo;s location, but really ended up needing to be viewable to the employee\u0026rsquo;s in the supervisor\u0026rsquo;s location and the direct reports in another location?   The question then turns on whether or not this information was in the \u0026ldquo;spec\u0026rdquo; or whether the business user didn\u0026rsquo;t let the developer know about it.  Now the question has created an ugly situation of \u0026ldquo;blame\u0026rdquo;.  Whose fault is it?\u003c/p\u003e","title":"Feature vs Bug - Does it Matter?"},{"content":"\nI felt like I was in a controlling relationship headed downhill. After two custom laptops returned for defective hardware, I wanted to leave. But leaving didn\u0026rsquo;t seem so easy after living in the walled garden of Apple all those years.\nThis blog post is about how to leave your Mac and return to OSS.\nMake a New Plan, Stan There are quite a few nice alternatives to the Mac Air out there. I decided to go with the new Sputnik 3. Some of my reasons:\nPowerful - New Haswell processor 13.3 inch touch display with 1920 x 1080 resolution Ships with Ubuntu 12.04 (64 bit) Nice design (yes looks are important) It arrived a couple of days before Christmas. The packaging itself was quite nice. Here is a picture next to my 13 inch Mac Air.\nThe best was that everything just \u0026ldquo;worked\u0026rdquo; out of the box. I had no problems configuring Ubuntu and getting the wireless network hooked up. I could close the lid and reopen it and have \u0026ldquo;instant on\u0026rdquo; just like the Mac Air. The keyboard is enjoyable to use and nicely backlit. The sleek design and light weight of the laptop is very comparable to the Mac Air.\nHop on the Bus, Gus It took my about a day to set up all my programs that I use on a daily basis. Here is a overview:\nApplication Dock/ Organization - Dash Ubuntu has a dock on the left hand side of the screen, that is very similar to the mac one. You can right click and pin applications to the dock to keep them in there. Clicking into the dash option, you can browse your applications that are installed.\nGetting New Apps - Ubuntu Software Center or apt-get You can install new applications easily by using the Ubuntu Software Center. Browsing the applications and installing them is point and click easy. If you don\u0026rsquo;t see the one you need or need a more recent version, you can always install via the command line with\nsudo apt-get install package-name Browser - Firefox or Chromium Ubuntu comes with Firefox and Chromium installed. You can also go with Chrome of course.\nMail - Thunderbird Ubuntu comes with Thunderbird mail ready to go. I was pleasantly surprised by how easy it was to setup Thunderbird Mail. You simply put in your email and password. Ubuntu keeps a configuration list of commonly used email providers. It automagically figured out the correct domains and ports to use. On the downside, it doesn\u0026rsquo;t do anything magic with your contacts. So you are on your own there. I also just found out about Geary, which looks pretty sweet.\nPassword Management - 1 Password Anywhere + Dropbox / LastPass There is not a linux client for 1Password. I can still use it by using 1PasswordAnywhere. I just have a bookmark to the 1PasswordAnyway link and I haz my logins. I am switching over to LastPass though, so you can edit / add new passwords. There is also an import utility to move stuff over from 1Password.\nEmacs Emacs just works :) It might be just me, but I think it is happier back on Ubuntu. I did an apt-get to get the 24 version.\nGit Client I went with gitg for a graphical Git client. It seems to have all the things you need.\nTerminal - Byobu Byobu Terminal comes already installed in Ubuntu. I have been taking it for a test drive and really like some of the features of easily adding new tabs, splitting screens and re-attaching to sessions.\nEvernote/ Everpad With Everpad, I can still use all my evernote stuff too.\nPresentations - LibreOffice / Reveal.js I have used Keynote heavily on the Mac. For existing presentations, I can convert them to ppt format and then modify or run in LibreOffice Impress. Most likely with all my new presentations, I will just use a JavaScript framework like reveal.js\nCommunication - Hipchat / Skype/ Google Hangouts / Campfire We use Hipchat for messaging at work. Hipchat has a linux client that works just the same. Skype also has a linux client. Of course, Google Hangouts is just fine on the web. I also use Campfire sometimes. There are a couple of linux clients out there, but I haven\u0026rsquo;t tried them yet. The web version works fine for me right now.\niPhone On my mac, I used to plug in my phone and sync to my dropbox. I tried plugging in my phone, but unfortunately, iOS7 put in a security feature to that prevents having the phone connect properly. The solution for me is to just use the phone dropbox app to sync the pictures automatically to my Dropbox.\nGet Yourself Free I don\u0026rsquo;t expect the road to free of bumps. I have only been using my new laptop for a week. But so far, it has been an enjoyable switch. The hardware is really impressive, and it feels good getting back to OSS.\nBest of all, I set myself free.\n","permalink":"https://gigasquidsoftware.com/blog/1/01/01/guide-to-leaving-your-mac-laptop/","summary":"\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/images/posts/0b962d76-11572063123_6baf3b35c2.jpg\"\u003e\u003c/p\u003e\n\u003cp\u003eI felt like I was in a controlling relationship headed downhill.\nAfter two custom laptops returned for defective hardware, I wanted to\nleave.  But leaving didn\u0026rsquo;t seem so easy after living in the walled\ngarden of Apple all those years.\u003c/p\u003e\n\u003cp\u003eThis blog post is about how to leave your Mac and return to OSS.\u003c/p\u003e\n\u003ch2 id=\"make-a-new-plan-stan\"\u003eMake a New Plan, Stan\u003c/h2\u003e\n\u003cp\u003eThere are quite a few nice alternatives to the Mac Air out there.\nI decided to go with the new\n\u003ca href=\"http://www.dell.com/us/business/p/xps-13-linux/pd\"\u003eSputnik 3\u003c/a\u003e.\nSome of my reasons:\u003c/p\u003e","title":"Guide to Leaving your Mac Laptop"}]