Clear Lines BlogMathias Brandewinder on quantitative analysis, .NET applications, Excel, decision making, and a whole lot of other random things.http://www.clear-lines.com/blog/
http://www.rssboard.org/rss-specificationBlogEngine.NET 1.6.1.0en-GBhttp://www.clear-lines.com/blog/opml.axdhttp://www.dotnetblogengine.net/syndication.axdMathias Brandewinder, Clear Lines ConsultingClear Lines Blog0.0000000.000000ClearLinesBloghttps://feedburner.google.comFirst impressions with DiffSharp, an F# autodiff library<p>A few weeks ago, I came across <a href="http://gbaydin.github.io/DiffSharp/">DiffSharp, an automatic differentiation library in F#</a>. As someone whose calculus skills have always been rather mediocre (thanks Wolfram Alpha!), but who needs to deal with gradients and the like on a regular basis because they are quite useful in machine learning and numerical methods, the project looked pretty interesting: who wouldn’t want exact and efficient calculations of derivatives? So I figured I would take a couple of hours to experiment with the library. This post is by no means an in-depth evaluation, but rather intended as “notes from the road” from someone entirely new to DiffSharp.</p> <h2>Basics</h2> <p>Suppose I want to compute the derivative of <em>f(x) = √ x</em> at, say, 42.0. Double-checking Wolfram Alpha confirms that <em>f</em> has derivative <em>f’(x) = 1 / (2 x √ x)</em> .</p> <p>Once DiffSharp is installed via Nuget, we can automatically evaluate <em>f’(x)</em> :</p> <pre class="brush: fsharp; gutter: false; toolbar: false;">#r @&quot;..\packages\DiffSharp.0.5.7\lib\DiffSharp.dll&quot;
open DiffSharp.AD.Forward
let f x = sqrt x
diff f 42. |&gt; printfn &quot;Evaluated: %f&quot;
1. / (2. * sqrt 42.) |&gt; printfn &quot;Actual: %f&quot;
Evaluated: 0.077152
Actual: 0.077152
val f : x:Dual -&gt; Dual
val it : unit = ()</pre>
<p>First off, obviously, it worked. Without any need for us to perform anything, DiffSharp took in our implementation of <em>f</em>, and computed the correct value. This is really nifty.</p>
<p>The piece which is interesting here is the inferred signature of <em>f</em>. If I were to remove the line that immediately follows the function declaration, <em>f</em> would have the following signature: </p>
<pre class="brush: fsharp; gutter: false; toolbar: false;">val f : x:float –&gt; float</pre>
<p>The moment you include the line diff f 42., the inferred type changes drastically, and becomes </p>
<pre class="brush: fsharp; gutter: false; toolbar: false;">val f : x:Dual –&gt; Dual</pre>
<p>This is pretty interesting. Because we call diff on <em>f</em>, which expects Duals (a type that is defined in DiffSharp), our function isn’t what we originally defined it to be – and calling f 42.0 at that point (for instance) will fail, because 42.0 is a float, and not a Dual. In other words, DiffSharp leverages type inference pretty aggressively, to convert functions into the form it needs to perform its magic.</p>
<p><em>Edit: Atilim Gunes Baydin suggested another way around that issue, which is inlining f. The following works perfectly well, and allows to both differentiate f, and use this against floats:</em></p>
<pre class="brush: fsharp; gutter: false; toolbar: false;">let inline f x = sqrt x
let f' = diff f
f 42.</pre>
<p><em>Thanks for the input!</em></p>
<p>This has a couple of implications. First, if you work in a script, you need to be careful about how you send your code to the F# interactive for execution. If you process the sample code above line by line in FSI, the evaluation will fail, because <em>f</em> will be inferred to be float –&gt; float. Then, you will potentially need to annotate your functions with type hints, to help inference. As an example, the following doesn’t work:</p>
<pre class="brush: fsharp; gutter: false; toolbar: false;">let g x = 3. * x
diff g 42.</pre>
<p>As is, <em>g</em> is still inferred to be of type float –&gt; float, because of the presence of the constant term, which is by default inferred as a float. That issue can be addressed at least two ways – by explicitly marking x or 3. as dual in g, like this:</p>
<pre class="brush: fsharp; gutter: false; toolbar: false;">let g x = (dual 3.) * x
let h (x:Dual) = 3. * x</pre>
<p>That’s how far we will go on this – if you want to dive in deeper, the <a href="http://gbaydin.github.io/DiffSharp/gettingstarted-typeinference.html">Type Inference</a> page discusses the topic in much greater detail</p>
<h2>A tiny example</h2>
<p>So why is this interesting? As I mentioned earlier, differentiation is used heavily in numeric algorithms to identify values that minimize a function, a prime example being the <a href="http://en.wikipedia.org/wiki/Gradient_descent">gradient descent algorithm</a>. The simplest example possible would be finding a (local) minimum of a single-argument function: starting from an arbitrary value x, we can iteratively follow the direction of steepest descent, until no significant change is observed.</p>
<p>Here is a quick-and-dirty implementation, using DiffSharp:</p>
<pre class="brush: fsharp; gutter: false; toolbar: false;">let minimize f x0 alpha epsilon =
let rec search x =
let fx' = diff f x
if fx' &lt; epsilon
then x
else
let x = x - alpha * fx'
search x
search x0</pre>
<p>Because DiffSharp handles the differentiation part automatically for us, with only 10 lines of code, we can now pass in arbitrary functions we want to minimize, and (with a few caveats…), and get a local minimum, no calculus needed:</p>
<pre class="brush: fsharp; gutter: false; toolbar: false;">let epsilon = 0.000001
let g (x:Dual) = 3. * pown x 2 + 2. * x + 1.
minimize g 0. 0.1 epsilon |&gt; printfn &quot;Min of g at x = %f&quot;
let h (x:Dual) = sin (pown (x + 30.) 2)
minimize h 0. 0.1 epsilon |&gt; printfn &quot;Min of h at x = %f&quot;
Min of g at x = -0.333333
Min of h at x = -0.397480</pre>
<p>Let’s make sure this is reasonable. <em>g</em> is a quadratic function, which has a minimum or maximum at –b/2*a, that is, –2 / 2 x 3 - this checks out. As for <em>h</em>, inspecting the function plot confirms that it has a minimum around the identified value:</p>
<p><a href="http://www.clear-lines.com/blog/image.axd?picture=function-plot.png"><img title="function-plot" style="border-left-width: 0px; border-right-width: 0px; border-bottom-width: 0px; display: inline; border-top-width: 0px" border="0" alt="function-plot" src="http://www.clear-lines.com/blog/image.axd?picture=function-plot_thumb.png" width="474" height="285" /></a> </p>
<h2>Conclusion</h2>
<p>I have barely started to scratch the surface of DiffSharp in this post, but so far, I really, really like its promise. While I limited my examples to single-variable functions, DiffSharp supports multivariate functions, and vector operations as well. The way it uses type inference is a bit challenging at first, but seems a reasonable price to pay for the resulting magic. My next step will probably be a less tiny example, perhaps a logistic regression against realistic data. I am very curious to try out the algebra bits – and also wondering in the back of my head how to best use the library in general. For instance, how easy is it to construct a function from external data, and turn it into the appropriate types for DiffSharp to work its magic? How well does this integrate with other libraries, say, Math.NET? We’ll see!</p>
<p>In the meanwhile, I’d recommend checking out the <a href="http://gbaydin.github.io/DiffSharp/">project page</a>, which happens to also be beautifully documented! And, as always, you can <a href="https://twitter.com/brandewinder">ping me on twitter</a> for comments or question.</p><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/ClearLinesBlog?a=VTTPS31EqkE:dj1gX-IS7Aw:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/ClearLinesBlog?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/ClearLinesBlog?a=VTTPS31EqkE:dj1gX-IS7Aw:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/ClearLinesBlog?i=VTTPS31EqkE:dj1gX-IS7Aw:D7DqB2pKExk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/ClearLinesBlog?a=VTTPS31EqkE:dj1gX-IS7Aw:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/ClearLinesBlog?i=VTTPS31EqkE:dj1gX-IS7Aw:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/ClearLinesBlog?a=VTTPS31EqkE:dj1gX-IS7Aw:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/ClearLinesBlog?i=VTTPS31EqkE:dj1gX-IS7Aw:V_sGLiPBpWU" border="0"></img></a>
</div><img src="//feeds.feedburner.com/~r/ClearLinesBlog/~4/VTTPS31EqkE" height="1" width="1" alt=""/>http://www.clear-lines.com/blog/post/First-impressions-with-DiffSharp-an-fsharp-autodiff-library.aspx
mathiashttp://www.clear-lines.com/blog/post/First-impressions-with-DiffSharp-an-fsharp-autodiff-library.aspx#commenthttp://www.clear-lines.com/blog/post.aspx?id=0c913cef-1943-4a98-aa3c-fd6b973ed7b8Sat, 21 Feb 2015 12:23:00 -1300mathiashttp://www.clear-lines.com/blog/pingback.axdhttp://www.clear-lines.com/blog/post.aspx?id=0c913cef-1943-4a98-aa3c-fd6b973ed7b80http://www.clear-lines.com/blog/trackback.axd?id=0c913cef-1943-4a98-aa3c-fd6b973ed7b8http://www.clear-lines.com/blog/post/First-impressions-with-DiffSharp-an-fsharp-autodiff-library.aspx#commenthttp://www.clear-lines.com/blog/syndication.axd?post=0c913cef-1943-4a98-aa3c-fd6b973ed7b8Fun with L-system<p>I had the great pleasure to speak at <a href="http://www.codemash.org/">CodeMash</a> this week, and, on my way back, ended up spending a couple of hours at the Atlanta airport waiting for my connecting flight back to the warmer climate of San Francisco – a perfect opportunity for some light-hearted coding fun. A couple of days earlier, I came across this really nice tweet, rendering the results of an L-system:</p> <p><blockquote class="twitter-tweet" lang="en"><p>{start:&#39;FFPF&#39;,rules:{F:&#39;PF++F[FF-F+PF+FPP][F]FFPF&#39;,P:&#39;&#39;},&#39;α&#39;:60} <a href="http://t.co/JZGDV4ghFy">pic.twitter.com/JZGDV4ghFy</a></p>&mdash; LSystemBot (@LSystemBot) <a href="https://twitter.com/LSystemBot/status/553954473694220288">January 10, 2015</a></blockquote> <script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script></p> <p>I ended up looking up <a href="http://en.wikipedia.org/wiki/L-system">L-systems on Wikipedia</a>, and thought this would make for some fun coding exercise. In a nutshell, a L-system is a grammar. It starts with an alphabet of symbols, and a set of rules which govern how each symbol can be transformed into another chain of symbols. By applying these rules to a starting state (the initial axiom), one can evolve it into a succession of states, which can be seen as the growth of an organism. And by mapping each symbol to operations in a <a href="http://en.wikipedia.org/wiki/Logo_%28programming_language%29">logo/turtle like language</a>, each generation can then be rendered as a graphic.</p> <p>So how could we go about coding this in F#? If you are impatient, you can find the final result as a <a href="https://gist.github.com/mathias-brandewinder/bcbac9e92901af564055">gist here</a>.</p> <p>First, I started with representing the core elements of an L-System with a couple of types:</p> <pre class="brush: fsharp; gutter: false; toolbar: false;">type Symbol = | Sym of char
type State = Symbol list
type Rules = Map&lt;Symbol,State&gt;
type LSystem =
{ Axiom:State
Rules:Rules }</pre>
<p>A symbol is a char, wrapped in a single-case discriminated union, and a State is simply a list of Symbols. We define the Rules that govern the transformation of Symbols by a Map, which associates a particular Symbol with a State, and an L-System is then an Axiom (the initial State), with a collection of Rules.</p>
<p>Let’s illustrate this on the second example from the Wikipedia page, the Pythagoras tree. Our grammar contains 4 symbols, 0, 1, [ and ], we start with a 0, and we have 2 rules, (1 → 11), and (0 → 1[0]0). This can be encoded in a straightforward manner in our domain, like this:</p>
<pre class="brush: fsharp; gutter: false; toolbar: false;">let lSystem =
{ Axiom = [ Sym('0') ]
Rules = [ Sym('1'), [ Sym('1'); Sym('1') ]
Sym('0'), [ Sym('1'); Sym('['); Sym('0'); Sym(']'); Sym('0') ]]
|&gt; Map.ofList }</pre>
<p>Growing the organism by applying the rules is fairly straightforward: given a State, we traverse the list of Symbols, look up for each of them if there is a matching rule, and perform a substitution if it is found, leaving it unchanged otherwise:</p>
<pre class="brush: fsharp; gutter: false; toolbar: false;">(*
Growing from the original axiom
by applying the rules
*)
let applyRules (rs:Rules) (s:Symbol) =
match (rs.TryFind s) with
| None -&gt; [s]
| Some(x) -&gt; x
let evolve (rs:Rules) (s:State) =
[ for sym in s do yield! (applyRules rs sym) ]
let forward (g:LSystem) =
let init = g.Axiom
let gen = evolve g.Rules
init |&gt; Seq.unfold (fun state -&gt; Some(state, gen state))
// compute nth generation of lSystem
let generation gen lSystem =
lSystem
|&gt; forward
|&gt; Seq.nth gen
|&gt; Seq.toList</pre>
<p>What does this give us on the Pythagoras Tree?</p>
<pre class="brush: fsharp; gutter: false; toolbar: false;">&gt; lSystem |&gt; generation 1;;
val it : Symbol list = [Sym '1'; Sym '['; Sym '0'; Sym ']'; Sym '0']</pre>
<p>Nice and crisp – that part is done. Next up, rendering. The idea here is that for each Symbol in a State, we will perform a substitution with a sequence of instructions, either a Move, drawing a line of a certain length, or a Turn of a certain Angle. We will also have a Stack, where we can Push or Pop the current position of the Turtle, so that we can for instance store the current position and direction on the stack, perform a couple of moves with a Push, and then return to the previous position by a Pop, which will reset the turtle to the previous position. Again, that lends itself to a very natural model:</p>
<pre class="brush: fsharp; gutter: false; toolbar: false;">(*
Modelling the Turtle/Logo instructions
*)
type Length = | Len of float
type Angle = | Deg of float
// override operator later
let add (a1:Angle) (a2:Angle) =
let d1 = match a1 with Deg(x) -&gt; x
let d2 = match a2 with Deg(x) -&gt; x
Deg(d1+d2)
type Inst =
| Move of Length
| Turn of Angle
| Push
| Pop
let Fwd x = Move(Len(x))
let Lft x = Turn(Deg(x))
let Rgt x = Turn(Deg(-x))</pre>
<p>We can now transform our L-system state into a list of instructions, and convert them into a sequence of Operations, in that case Drawing lines between 2 points:</p>
<pre class="brush: fsharp; gutter: false; toolbar: false;">type Pos = { X:float; Y:float; }
type Dir = { L:Length; A:Angle }
type Turtle = { Pos:Pos; Dir:Dir }
type ProgState = { Curr:Turtle; Stack:Turtle list }
let turn angle turtle =
let a = turtle.Dir.A |&gt; add angle
{ turtle with Dir = { turtle.Dir with A = a } }
type Translation = Map&lt;Symbol,Inst list&gt;
type Ops = | Draw of Pos * Pos
let pi = System.Math.PI
let line (pos:Pos) (len:Length) (ang:Angle) =
let l = match len with | Len(l) -&gt; l
let a = match ang with | Deg(a) -&gt; (a * pi / 180.)
{ X = pos.X + l * cos a ; Y = pos.Y + l * sin a }
let execute (inst:Inst) (state:ProgState) =
match inst with
| Push -&gt; None, { state with Stack = state.Curr :: state.Stack }
| Pop -&gt;
let head::tail = state.Stack // assumes more Push than Pop
None, { state with Curr = head; Stack = tail }
| Turn(angle) -&gt;
None, { state with Curr = state.Curr |&gt; turn angle }
| Move(len) -&gt;
let startPoint = state.Curr.Pos
let endPoint = line startPoint len state.Curr.Dir.A
Some(Draw(startPoint,endPoint)), { state with Curr = { state.Curr with Pos = endPoint } }
let toTurtle (T:Translation) (xs:Symbol list) =
let startPos = { X = 400.; Y = 400. }
let startDir = { L = Len(0.); A = Deg(0.) }
let init =
{ Curr = { Pos = startPos; Dir = startDir }
Stack = [] }
xs
|&gt; List.map (fun sym -&gt; T.[sym])
|&gt; List.concat
|&gt; Seq.scan (fun (op,state) inst -&gt; execute inst state) (None,init)
|&gt; Seq.map fst
|&gt; Seq.choose id</pre>
<p>We simply map each Symbol to a List of instructions, transform the list of symbols into a list of instructions, and maintain at each step the current position and direction, as well as a Stack (represented as a list) of positions and directions. How does it play out on our Pythagoras Tree? First, we define the mapping from Symbols to Instructions:</p>
<pre class="brush: fsharp; gutter: false; toolbar: false;">let l = 1.
let T =
[ Sym('0'), [ Fwd l; ]
Sym('1'), [ Fwd l; ]
Sym('['), [ Push; Lft 45.; ]
Sym(']'), [ Pop; Rgt 45.; ] ]
|&gt; Map.ofList</pre>
<p>… and we simply send that toTurtle, which produces a list of Draw instructions:</p>
<pre class="brush: fsharp; gutter: false; toolbar: false;">&gt; lSystem |&gt; generation 1 |&gt; toTurtle T;;
val it : seq&lt;Ops&gt; =
seq
[Draw ({X = 400.0;
Y = 400.0;},{X = 401.0;
Y = 400.0;}); Draw ({X = 401.0;
Y = 400.0;},{X = 401.7071068;
Y = 400.7071068;});
Draw ({X = 401.0;
Y = 400.0;},{X = 401.7071068;
Y = 399.2928932;})]</pre>
<p>Last step – some pretty pictures. We’ll simply generate a html document, rendering the image using SVG, by creating one SVG line per Draw instruction:</p>
<pre class="brush: fsharp; gutter: false; toolbar: false;">let header = &quot;&quot;&quot;
&lt;!DOCTYPE html&gt;
&lt;html&gt;
&lt;body&gt;
&lt;svg height=&quot;800&quot; width=&quot;800&quot;&gt;&quot;&quot;&quot;
let footer = &quot;&quot;&quot;
&lt;/svg&gt;
&lt;/body&gt;
&lt;/html&gt;
&quot;&quot;&quot;
let toSvg (ops:Ops seq) =
let asString (op:Ops) =
match op with
| Draw(p1,p2) -&gt; sprintf &quot;&quot;&quot;&lt;line x1=&quot;%f&quot; y1=&quot;%f&quot; x2=&quot;%f&quot; y2=&quot;%f&quot; style=&quot;stroke:rgb(0,0,0);stroke-width:1&quot; /&gt;&quot;&quot;&quot; p1.X p1.Y p2.X p2.Y
[ yield header
for op in ops -&gt; asString op
yield footer ]
|&gt; String.concat &quot;\n&quot;
open System.IO
let path = &quot;C:/users/mathias/desktop/lsystem.html&quot;
let save template = File.WriteAllText(path,template)</pre>
<p>And we are pretty much done:</p>
<pre class="brush: fsharp; gutter: false; toolbar: false;">&gt; lSystem |&gt; generation 8 |&gt; toTurtle T |&gt; toSvg |&gt; save;;
val it : unit = ()</pre>
<p>… which produces the following graphic: </p>
<p><a href="http://www.clear-lines.com/blog/image.axd?picture=image_66.png"><img title="image" style="border-top: 0px; border-right: 0px; border-bottom: 0px; border-left: 0px; display: inline" border="0" alt="image" src="http://www.clear-lines.com/blog/image.axd?picture=image_thumb_66.png" width="280" height="248" /></a> </p>
<p>Pretty neat! Just for fun, I replicated the <a href="http://en.wikipedia.org/wiki/L-system#Example_5:_Sierpinski_triangle">Sierpinski Triangle</a> example as well:</p>
<pre class="brush: fsharp; gutter: false; toolbar: false;">let sierpinski () =
let lSystem =
{ Axiom = [ Sym('A') ]
Rules = [ Sym('A'), [ Sym('B'); Sym('&gt;'); Sym('A'); Sym('&gt;'); Sym('B') ]
Sym('B'), [ Sym('A'); Sym('&lt;'); Sym('B'); Sym('&lt;'); Sym('A') ]]
|&gt; Map.ofList }
let l = 1.
let T =
[ Sym('A'), [ Fwd l; ]
Sym('B'), [ Fwd l; ]
Sym('&gt;'), [ Lft 60.; ]
Sym('&lt;'), [ Rgt 60.; ] ]
|&gt; Map.ofList
lSystem
|&gt; generation 9
|&gt; toTurtle T
|&gt; toSvg
|&gt; save</pre>
<p>… which results in the following picture:</p>
<p><a href="http://www.clear-lines.com/blog/image.axd?picture=image_67.png"><img title="image" style="border-top: 0px; border-right: 0px; border-bottom: 0px; border-left: 0px; display: inline" border="0" alt="image" src="http://www.clear-lines.com/blog/image.axd?picture=image_thumb_67.png" width="525" height="453" /></a> </p>
<p>That’s it for tonight! I had a lot of fun coding this (it certainly made the flight less boring), and found the idea of converting code to turtle instructions, with a stack, pretty interesting. Hope you enjoyed it, and if you end up playing with this, share your creations on Twitter and ping me at <a href="https://twitter.com/brandewinder">@brandewinder</a>!</p>
<p><a href="https://gist.github.com/mathias-brandewinder/bcbac9e92901af564055">Gist for the whole code here</a></p><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/ClearLinesBlog?a=29gHtIdU9Fk:D56ZCsTypm4:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/ClearLinesBlog?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/ClearLinesBlog?a=29gHtIdU9Fk:D56ZCsTypm4:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/ClearLinesBlog?i=29gHtIdU9Fk:D56ZCsTypm4:D7DqB2pKExk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/ClearLinesBlog?a=29gHtIdU9Fk:D56ZCsTypm4:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/ClearLinesBlog?i=29gHtIdU9Fk:D56ZCsTypm4:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/ClearLinesBlog?a=29gHtIdU9Fk:D56ZCsTypm4:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/ClearLinesBlog?i=29gHtIdU9Fk:D56ZCsTypm4:V_sGLiPBpWU" border="0"></img></a>
</div><img src="//feeds.feedburner.com/~r/ClearLinesBlog/~4/29gHtIdU9Fk" height="1" width="1" alt=""/>http://www.clear-lines.com/blog/post/Fun-with-L-system.aspx
mathiashttp://www.clear-lines.com/blog/post/Fun-with-L-system.aspx#commenthttp://www.clear-lines.com/blog/post.aspx?id=29c93a30-5a76-450d-9a16-89efe32c008fSun, 11 Jan 2015 18:37:00 -1300F#mathiashttp://www.clear-lines.com/blog/pingback.axdhttp://www.clear-lines.com/blog/post.aspx?id=29c93a30-5a76-450d-9a16-89efe32c008f1http://www.clear-lines.com/blog/trackback.axd?id=29c93a30-5a76-450d-9a16-89efe32c008fhttp://www.clear-lines.com/blog/post/Fun-with-L-system.aspx#commenthttp://www.clear-lines.com/blog/syndication.axd?post=29c93a30-5a76-450d-9a16-89efe32c008fThe 2014 F# Tour in numbers<p>Well, we are in the last hours of 2014, and I am nearly recovered from the craziness that was the <a href="http://clear-lines.com/blog/post/fsharp-europe-tour-2014.aspx">F# Europa Tour 2014</a>, so here we go – the Tour, in cold, hard facts (after all, I am a numbers’ guy):</p> <ul> <li>40 days of travelling across Europe.</li> <li>16 talks.</li> <li>5 workshops (about 50 hours total).</li> <li>9 countries.</li> <li>6991 miles (11,250 kilometers) travelled, roughly (this is straight-line city to city, so the actual number is probably a good deal larger).</li> <li>14 hours of bus.</li> <li>roughly 50 hours of train.</li> <li>roughly 28 hours of plane.</li> <li>12 cities visited (and spoken at!).</li> <li>I lost track of how many gallons of beer were ingested. This is big data.</li> <li>500 attendees? Maybe more? See previous data point.</li> <li>Delivered hundreds of shiny <a href="http://fsharp.org/">fsharp.org stickers</a> to F# Communities across Europe. [btw, in case you didn't hear - the F# Software Foundation is now a full-fledged, legally established entity, and <a href="http://foundation.fsharp.org/join">YOU can be a member. Check it out!</a>]</li> </ul> <p><iframe src="https://www.google.com/maps/d/embed?mid=zJ4Wo5XaR4h8.k8AKySfC_hGs" width="640" height="480"></iframe></p>
<p>Now for the important qualitative questions:</p> <ul> <li>Where did I eat the best bacon? This came as a surprise to me, but I have to say, the bacon I ate in Dublin, Ireland was amazing. Twice.</li> <li>Where does one find the best beer in Europe? This is a hard one – I had a chance to sample great beers from all over the place. I would say, Munich and its Biergarten rules, but the live beers at BuildStuff in Vilnius, Lithuania, were a very nice surprise.</li> <li>What’s the weirdest thing I ate? This one goes to Norway and its <a href="http://en.wikipedia.org/wiki/Lutefisk">Lutefisk</a>, a traditional Christmas fish dish. It’s definitely a regional specialty, as in, a specialty which didn’t expand beyond a limited regional area, for good reasons. For the record, I actually enjoyed it!</li> <li>What was the worst travelling mistake? Booking a last minute train ticket from Paris to Aarhus, Denmark, to realize in the train that instead of a nice sleeping car, I would be spending 22 hours sitting in a train with no food on board.</li> <li>Biggest scare: every person who has given a talk will tell you, relying on the internet and anything live in a presentation is a rookie mistake. This is great advice, which is why I completely ignored it. It all worked just fine, but learning that Azure had been down for a couple of hours, right before a talk at BuildStuff which 100% required a live deployment to Azure to work, did give me some cold sweat.</li> </ul> <p>Would I do it again? In a heartbeat! It was a bit crazy, and definitely exhausting, but a ton of fun. All of you who helped out making this happen, from the bottom of my heart, thank you! The F# Community is absolutely fantastic, packed with energy and a good, friendly vibe, and everywhere I went felt like family. You all kept me going, so again, thank you (you know who you are)! In the meanwhile, I wish you all a happy year 2015 ahead, let’s make that one even better than 2014, and I hope to see many of you again this year! And, as always, feel free to <a href="https://twitter.com/brandewinder/">ping me on Twitter as @brandewinder</a>.</p> <blockquote class="twitter-tweet" lang="en"><p>Obviously, the F# Europe tour has arrived in Munich. Prost! <a href="https://twitter.com/hashtag/fsharp?src=hash">#fsharp</a> <a href="http://t.co/vP3VG6n8Of">pic.twitter.com/vP3VG6n8Of</a></p>&mdash; Mathias Brandewinder (@brandewinder) <a href="https://twitter.com/brandewinder/status/532273358348763136">November 11, 2014</a></blockquote> <script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script> <blockquote class="twitter-tweet" lang="en"><p>... and the F# tour is now in Vilnius! Live beer, grand time &amp; awesome people. <a href="https://twitter.com/hashtag/buildstufflt?src=hash">#buildstufflt</a> <a href="https://twitter.com/hashtag/fsharp?src=hash">#fsharp</a> <a href="http://t.co/kIJBhQNOwP">pic.twitter.com/kIJBhQNOwP</a></p>&mdash; Mathias Brandewinder (@brandewinder) <a href="https://twitter.com/brandewinder/status/535157675529887745">November 19, 2014</a></blockquote> <script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script> <blockquote class="twitter-tweet" lang="en"><p>In case you wondered, <a href="https://twitter.com/sforkmann">@sforkmann</a> is not ALWAYS working on <a href="https://twitter.com/Paket">@paket</a>. Here he is helping <a href="https://twitter.com/altnetberlin">@altnetberlin</a> <a href="https://twitter.com/hashtag/fsharp?src=hash">#fsharp</a> dojo <a href="http://t.co/BcW8JnP7mM">pic.twitter.com/BcW8JnP7mM</a></p>&mdash; Mathias Brandewinder (@brandewinder) <a href="https://twitter.com/brandewinder/status/537691908395773952">November 26, 2014</a></blockquote> <script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script> <blockquote class="twitter-tweet" lang="en"><p>Nice crowd for <a href="https://twitter.com/NNUGBergen">@nnugbergen</a> F# <a href="https://twitter.com/hashtag/machinelearning?src=hash">#machinelearning</a> hands-on, VS, emacs, vim, XS &amp; monodevelop in the house! <a href="https://twitter.com/hashtag/fsharp?src=hash">#fsharp</a> <a href="http://t.co/fu0SkkSnZV">pic.twitter.com/fu0SkkSnZV</a></p>&mdash; Mathias Brandewinder (@brandewinder) <a href="https://twitter.com/brandewinder/status/542759137797754880">December 10, 2014</a></blockquote> <script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/ClearLinesBlog?a=PSY0kl0tns8:Sz2QnhNzK1o:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/ClearLinesBlog?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/ClearLinesBlog?a=PSY0kl0tns8:Sz2QnhNzK1o:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/ClearLinesBlog?i=PSY0kl0tns8:Sz2QnhNzK1o:D7DqB2pKExk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/ClearLinesBlog?a=PSY0kl0tns8:Sz2QnhNzK1o:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/ClearLinesBlog?i=PSY0kl0tns8:Sz2QnhNzK1o:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/ClearLinesBlog?a=PSY0kl0tns8:Sz2QnhNzK1o:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/ClearLinesBlog?i=PSY0kl0tns8:Sz2QnhNzK1o:V_sGLiPBpWU" border="0"></img></a>
</div><img src="//feeds.feedburner.com/~r/ClearLinesBlog/~4/PSY0kl0tns8" height="1" width="1" alt=""/>http://www.clear-lines.com/blog/post/The-2014-F-Tour-in-numbers.aspx
mathiashttp://www.clear-lines.com/blog/post/The-2014-F-Tour-in-numbers.aspx#commenthttp://www.clear-lines.com/blog/post.aspx?id=693661d4-cbff-4a33-96a2-b47f3c6e9665Wed, 31 Dec 2014 10:59:00 -1300F#mathiashttp://www.clear-lines.com/blog/pingback.axdhttp://www.clear-lines.com/blog/post.aspx?id=693661d4-cbff-4a33-96a2-b47f3c6e96651http://www.clear-lines.com/blog/trackback.axd?id=693661d4-cbff-4a33-96a2-b47f3c6e9665http://www.clear-lines.com/blog/post/The-2014-F-Tour-in-numbers.aspx#commenthttp://www.clear-lines.com/blog/syndication.axd?post=693661d4-cbff-4a33-96a2-b47f3c6e9665Textogramme<p><em>This post is December 20th' part of the <a href="https://sergeytihon.wordpress.com/2014/11/24/f-advent-calendar-in-english-2014/">English F# Advent</a>&#160;<a href="https://twitter.com/search?q=%23fsadvent">#fsAdvent</a> series; make sure to also check out the <a href="http://connpass.com/event/9758/">Japanese series</a>, which also packs the awesome!</em> </p> <p>As I was going around Paris the other day, I ended up in the Concorde metro station. Instead of the standard issue white tiles, this station is decorated with the French constitution, rendered as a mosaic of letters.</p> <p><a href="http://fr.wikipedia.org/wiki/Concorde_(m%C3%A9tro_de_Paris)#Galerie_de_photos"><img title="" style="border-left-width: 0px; border-right-width: 0px; border-bottom-width: 0px; display: inline; border-top-width: 0px" border="0" alt="" src="http://www.clear-lines.com/blog/image.axd?picture=Metro-Concorde.jpg" width="244" height="184" /></a> </p> <p>[<a href="http://fr.wikipedia.org/wiki/Concorde_(m%C3%A9tro_de_Paris)">Source: Wikipedia</a>]</p> <p>My mind started wandering, and by some weird association, it reminded me of <a href="http://en.wikipedia.org/wiki/Calligrammes">Calligrammes</a>, a collection of poems by Guillaume Apollinaire, where words are arranged on the page to depict images that compliment the text itself.</p> <p><a href="http://en.wikipedia.org/wiki/Calligrammes"><img title="Guillaume-Apollinaire-Calligramme-La_Mandoline,_l’œillet_et_le_bambou" style="border-left-width: 0px; border-right-width: 0px; border-bottom-width: 0px; display: inline; border-top-width: 0px" border="0" alt="Guillaume-Apollinaire-Calligramme-La_Mandoline,_l’œillet_et_le_bambou" src="http://www.clear-lines.com/blog/image.axd?picture=Guillaume-Apollinaire-Calligramme-La_Mandoline,_l%E2%80%99%C5%93illet_et_le_bambou.png" width="187" height="244" /></a> </p> <p>[<a href="http://en.wikipedia.org/wiki/Calligrammes">Source: Wikipedia</a>]</p> <p>After some more drifting, I started wondering if I could use this as an inspiration for some playful F# fun. How about taking a piece of text, an image, and fusing them into one? </p> <p>There are many ways one could approach this; being rather lazy, I thought a reasonably simple direction would be to decompose the original image into dark and light blocks, and fill them with the desired text. As simple as it may sound, the task is not entirely trivial. First, we need to decide on an appropriate threshold to separate &quot;dark&quot; and &quot;light&quot; areas on the image, to get a contrast good enough to recognize the image rendered in black &amp; white. Then, we also have to resize the image appropriately into a new grid, where the characters from the original text fit the mapped dark area as closely as possible. </p> <p><em>Note: I don't think the warning &quot;don't put this in production, kids&quot; is useful, unless someone thinks there is a market for Calligramme as a Service. However, I'll say this: this is me on &quot;vacation hacking fun&quot; mode, so yes, there are quite probably flaws in that code. I put it up as a </em><a href="https://gist.github.com/mathias-brandewinder/ec37edfad6bf5a7ca2ff"><em>Gist here</em></a><em> - flame away, or tell me how to make it better on Twitter ;)</em></p> <p></p> <h2>Separating dark and light </h2> <p>So how could we go about splitting an image into dark and light pixels? First, we can using the color brightness from the System.Drawing namespace to determine how light the color of an individual pixel is: </p> <pre class="brush: fsharp; gutter: false; toolbar: false;">open System.Drawing
let brightness (c:Color) = c.GetBrightness ()
let pixels (bmp:Bitmap) =
seq { for x in 0 .. bmp.Width - 1 do
for y in 0 .. bmp.Height - 1 -&gt;
(x,y) |&gt; bmp.GetPixel }</pre>
<p> We still need to decide what boundary to use to separate the image between dark and light. What we want in the end is an image which is reasonably balanced, that is, it should be neither overwhelmingly dark or light. A simple way to enforce that is to arbitrarily constrain one third of the pixels at least to be either dark or light. Then, we want a boundary value that is as clear cut as possible, for instance by finding a value with a large brightness change margin. Let's do that: </p>
<pre class="brush: fsharp; gutter: false; toolbar: false;">let breakpoint (bmp:Bitmap) =
let pixelsCount = bmp.Width * bmp.Height
let oneThird = pixelsCount / 3
let pixs = pixels bmp
let threshold =
pixs
|&gt; Seq.map brightness
|&gt; Seq.sort
|&gt; Seq.pairwise
|&gt; Seq.skip oneThird
|&gt; Seq.take oneThird
|&gt; Seq.maxBy (fun (b0,b1) -&gt; b1 - b0)
|&gt; snd
let darkPixels =
pixs
|&gt; Seq.map brightness
|&gt; Seq.filter ((&gt;) threshold)
|&gt; Seq.length
(threshold,darkPixels)</pre>
<p> We iterate over every pixel, sort them by brightness, retain only the middle third, and look for the largest brightness increase. Done - breakpoint returns both the threshold value (the lightness level which decides whether a pixel will be classified as dark or light), as well as how many pixels will be marked as dark. </p>
<h2>Resizing</h2>
<p>Now that we have a boundary value, and know how many pixels will be marked as dark, we need to determine the size of the grid where our text will be mapped. Ignoring for a moment rounding issues, let's figure out a reasonable size for our grid. </p>
<p>First, how many characters do we need? We know the number of dark pixels in the original image - and in our target image, we want the same ratio of text to white space, so the total number of characters we'll want in our final image will be roughly <em>total chars ~ text length * dark pixels / (width * height)</em>. </p>
<p>Then, what should the width of the target image, in characters? First, we want [1] <em>target width * target height ~ total chars</em>. Then, ideally, the proportions of the target image should be similar to the original image, so <em>target width / target height ~ width / height</em>, which gives us <em>target height ~ target width * height / width</em>. Substituting in [1] gives us <em>target width * target width * height / width ~ total chars</em>, which simplifies to <em>target width ~ sqrt (total chars * width / height)</em>. </p>
<p>Translating this to code, conveniently ignoring all the rounding issues, we get: </p>
<pre class="brush: fsharp; gutter: false; toolbar: false;">let sizeFor (bmp:Bitmap) (text:string) darkPixels =
let width,height = bmp.Width, bmp.Height
let pixels = width * height
let textLength = text.Length
let chars = textLength * pixels / darkPixels
let w = (chars * width / height) |&gt; float |&gt; sqrt |&gt; int
let h = (w * height) / width
(w,h)</pre>
<h2>Rendering </h2>
<p>Good, now we are about ready to get down to business. We have an original image, a threshold to determine which pixels to consider dark or light, and a &quot;target grid&quot; of known width and height. What we need now is to map every cell of our final grid to the original image, decide whether it should be dark or light, and if dark, write a character from our text. </p>
<p>Ugh. More approximation ahead. At that point, there is no chance that the cells from our target grid map the pixels from the original image one to one. What should we do? This is my Christmas vacation time, a time of rest and peace, so what we will do is be lazy again. For each cell in the target grid, we will retrieve the pixels that it overlaps on the original image, and simply average out their brightness, not even bothering with a weighted average based on their overlap surface. As other lazy people before me nicely put it, &quot;we'll leave that as an exercise to the reader&quot;. </p>
<p>Anyways, here is the result, a mapping function that returns the coordinates of the pixels intersected by a cell, as well as a reducer, averaging the aforementioned pixels by brightness, and a somewhat un-necessary function that transforms the original image in a 2D array of booleans, marking where a letter should go (I mainly created it because I had a hard time keeping track of rows and columns): </p>
<pre class="brush: fsharp; gutter: false; toolbar: false;">let mappedPixels (bmp:Bitmap) (width,height) (x,y) =
let wScale = float bmp.Width / float width
let hScale = float bmp.Height / float height
let loCol = int (wScale * float x)
let hiCol =
int (wScale * float (x + 1)) - 1
|&gt; min (bmp.Width - 1)
let loRow = int (hScale * float y)
let hiRow =
int (hScale * float (y + 1)) - 1
|&gt; min (bmp.Width - 1)
seq { for col in loCol .. hiCol do
for row in loRow .. hiRow -&gt; (col,row) }
let reducer (img:Bitmap) pixs =
pixs
|&gt; Seq.map img.GetPixel
|&gt; Seq.averageBy brightness
let simplified (bmp:Bitmap) (width,height) threshold =
let map = mappedPixels bmp (width,height)
let reduce = reducer bmp
let isDark value = value &lt; threshold
let hasLetter = map &gt;&gt; reduce &gt;&gt; isDark
Array2D.init width height (fun col row -&gt;
(col,row) |&gt; hasLetter)</pre>
<p>Almost there - wrap this with 2 functions, applyTo to transform the text into a sequence, and rebuild, to recreate the final string function: </p>
<pre class="brush: fsharp; gutter: false; toolbar: false;">let applyTo (bmp:Bitmap) (width,height) threshold (text:string) =
let chars = text |&gt; Seq.toList
let image = simplified bmp (width,height) threshold
let nextPosition (col,row) =
match (col &lt; width - 1) with
| true -&gt; (col+1,row)
| false -&gt; (0,row+1)
(chars,(0,0))
|&gt; Seq.unfold (fun (cs,(col,row)) -&gt;
let next = nextPosition (col,row)
match cs with
| [] -&gt; Some(' ',(cs,next))
| c::tail -&gt;
if image.[col,row]
then
Some(c,(tail,next))
else Some(' ',(cs,next)))
let rebuild (width,height) (data:char seq) =
seq { for row in 0 .. height - 1 -&gt;
data
|&gt; Seq.map string
|&gt; Seq.skip (row * width)
|&gt; Seq.take width
|&gt; Seq.toArray
|&gt; (String.concat &quot;&quot;) }
|&gt; (String.concat &quot;\n&quot;)</pre>
<h2>Trying it out </h2>
<p>Let's test this out, using the <a href="http://fsharp.org/foundation/logo.html">F# Software Foundation logo</a> as an image, and the following text, from fsharp.org, as a filler:</p>
<blockquote>
<p>F# is a mature, open source, cross-platform, functional-first programming language. It empowers users and organizations to tackle complex computing problems with simple, maintainable and robust code.</p>
</blockquote>
<p>Run this through the grinder…</p>
<pre class="brush: fsharp; gutter: false; toolbar: false;">let path = @&quot;c:/users/mathias/pictures/fsharp-logo.jpg&quot;
let bmp = new Bitmap(path)
let text = &quot;&quot;&quot;F# is // snipped // &quot;&quot;&quot;
let threshold,darkPixels = breakpoint bmp
let width,height = sizeFor bmp text darkPixels
text
|&gt; applyTo bmp (width,height) threshold
|&gt; rebuild (width,height)</pre>
<p>… and we get the following: </p>
<pre>
F#
is
a matu
re, open
source, c
ross-platfor
m, fun ctiona
l-firs t progr
amming l anguag
e. It emp owers
users and organi
zation s to tackle
compl ex computi
ng pro bl ems wit
h simp l e, main
tainab le and
robust code. </pre>
<p>Not too bad! The general shape of the logo is fairly recognizable, with some happy accidents, like for instance isolating &quot;fun&quot; in &quot;functional&quot;. However, quite a bit of space has been left empty, most likely because of the multiple approximations we did along the way. </p>
<h2>Improved resizing </h2>
<p>Let's face it, I do have some obsessive-compulsive behaviors. As lazy as I feel during this holiday break, I can't let go of this sloppy sizing issue. We can't guarantee a perfect fit (there might simply not be one), but maybe we can do a bit better than our initial sizing guess. Let's write a mini solver, a recursive function that will iteratively attempt to improve the fit. </p>
<p>Given a current size and count of dark cells, if the text is too long to fit, the solver will simply expand the target grid size, adding one row or one column, picking the one that keeps the grid horizonal/vertical proportions closest to the image. If the text fits better in the new solution, keep searching, otherwise, done (similarly, reduce the size if the text is too short to fit). </p>
<p>For the sake of brevity, I won't include the solver code here in the post. If you are interested, you can <a href="https://gist.github.com/mathias-brandewinder/ec37edfad6bf5a7ca2ff">find it in the gist here</a>. </p>
<p>Below are the results of the original and shiny new code, which I ran on a slightly longer bit of text. </p>
<p>Before: </p>
<pre>
F#is
amatur
eopenso
urcecross
-platformfun
ctional-firstp
rogramminglangua
geItempowersusersa
ndorganiz ationstot
acklecomp lexcomput
ingproble ms withsimpl
emaintain abl eandrobus
tcodeF#ru nson LinuxMacO
SXAndroid iOSWi ndowsGPUs
andbrowse rsItis freetouse
andisope nsourc eunderanO
SI-approv edlic enseF#isu
sedinawid eran geofappli
cationar eas andissuppo
rtedbybo th anactive
opencommu nityandin
dustry-le adingcomp
aniesprovidingpr
ofessionaltool
s </pre>
<p>… and after:</p>
<pre>
F #
is am
atu reo
pens ourc
ecros s-pla
tformf unctio
nal-fir stprogr
ammingla nguageIt
empowers usersand
organiza t ionstota
cklecomp le xcomputi
ngproble msw ithsimpl
emaintai nabl eandrobu
stcodeF# runso nLinuxMac
OSXAndro idiOS WindowsGP
Usandbro wsers Itisfreet
ouseandi sope nsourceun
deranOSI -ap provedlic
enseF#is us edinawide
rangeofa p plication
areasand issupport
edbyboth anactive
opencom munitya
ndindu stry-l
eadin gcomp
anie spro
vid ing
pr of
e s </pre>
<p>We still have a small mismatch, but the fit is much better.</p>
<p>And this concludes our F# Advent post! This was a rather useless exercise, but then, the holidays are about fun rather than productivity. I had fun doing this, and hope you had some fun reading it. In the meanwhile, I wish you all a holiday period full of fun and happiness, and… see you in 2015! And, as always, you can <a href="http://www.twitter.com/brandewinder">ping me on twitter</a> if you have comments or questions. Cheers!</p><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/ClearLinesBlog?a=agq2s-2W5I4:kUN9lZ87pHc:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/ClearLinesBlog?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/ClearLinesBlog?a=agq2s-2W5I4:kUN9lZ87pHc:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/ClearLinesBlog?i=agq2s-2W5I4:kUN9lZ87pHc:D7DqB2pKExk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/ClearLinesBlog?a=agq2s-2W5I4:kUN9lZ87pHc:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/ClearLinesBlog?i=agq2s-2W5I4:kUN9lZ87pHc:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/ClearLinesBlog?a=agq2s-2W5I4:kUN9lZ87pHc:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/ClearLinesBlog?i=agq2s-2W5I4:kUN9lZ87pHc:V_sGLiPBpWU" border="0"></img></a>
</div><img src="//feeds.feedburner.com/~r/ClearLinesBlog/~4/agq2s-2W5I4" height="1" width="1" alt=""/>http://www.clear-lines.com/blog/post/Textogramme.aspx
tryphonhttp://www.clear-lines.com/blog/post/Textogramme.aspx#commenthttp://www.clear-lines.com/blog/post.aspx?id=67c68ab7-6187-4d2e-b2ba-b876dc610587Sat, 20 Dec 2014 01:55:23 -1300F#tryphonhttp://www.clear-lines.com/blog/pingback.axdhttp://www.clear-lines.com/blog/post.aspx?id=67c68ab7-6187-4d2e-b2ba-b876dc6105873http://www.clear-lines.com/blog/trackback.axd?id=67c68ab7-6187-4d2e-b2ba-b876dc610587http://www.clear-lines.com/blog/post/Textogramme.aspx#commenthttp://www.clear-lines.com/blog/syndication.axd?post=67c68ab7-6187-4d2e-b2ba-b876dc610587Some completely useless fun with the logistic map<p>From time to time, I get absorbed by questions for no clear reason. This is one of these times &ndash; you have been warned.</p>
<p>So here is the question: can I use a logistic map to encode an arbitrary list of 1s and 0s into a single float, and generate back the series by applying the logistic map? I don&rsquo;t think there is a clear theoretical or practical interest in this question, but for some reason I couldn&rsquo;t shake it off, and had to do it.</p>
<p>Just to clarify a bit what I have in mind, here is the expression for the <a href="http://en.wikipedia.org/wiki/Logistic_map">logistic map</a>:</p>
<p>x(n+1) = alpha * x(n) * (1-x(n))</p>
<p>This is a recurrence relation, and has been well studied, because it illustrates very nicely some important ideas in chaos theory. In particular, for x0 in ] 0.0; 1.0 [ and values of alpha between 0 and 4, the series will remain in the interval ] 0.0; 1.0 [, and for certain values of alpha, 4.0 for instance, the series will exhibit a chaotic behavior.</p>
<p><a href="http://www.clear-lines.com/blog/image.axd?picture=logistic.png"><img style="border-top: 0px; border-right: 0px; border-bottom: 0px; border-left: 0px; display: inline" title="logistic" src="http://www.clear-lines.com/blog/image.axd?picture=logistic_thumb.png" border="0" alt="logistic" width="244" height="119" /></a></p>
<p>Anyways &ndash; so here is what I have in mind. If I gave you an arbitrary float in the unit interval, I could &ldquo;decrypt&rdquo; binary values this way:</p>
<pre class="brush: fsharp; gutter: false; toolbar: false;">let f x = 4. * x * (1. - x)
let decrypt root =
root
|&gt; Seq.unfold (fun x -&gt; Some(x, f x))
|&gt; Seq.map (fun x -&gt; if x &gt; 0.5 then 1 else 0)
let test = decrypt 0.12345 |&gt; Seq.take 20 |&gt; Seq.toList</pre>
<p>Running that example produces the following result:</p>
<p><span style="font-family: Consolas;">val test : int list = <br />&nbsp; [1; 1; 0; 1; 1; 1; 1; 0; 0; 1; 0; 1; 1; 0; 1; 1; 0; 0; 0; 1; 1; 1; 0; 0; 0; <br />&nbsp;&nbsp; 1; 1; 0; 1; 0; 0; 0; 1; 0; 1; 1; 0; 0; 0; 1; 0; 0; 0; 1; 0; 1; 1; 1; 1; 1; <br />&nbsp;&nbsp; 1; 1; 0; 1; 0; 0; 1; 1; 0; 0; 0; 1; 1]</span></p>
<p>This illustrates how, from a single float value, in this case, 0.12345, I could generate a list of 0s and 1s. The question is, can I generate any sequence? That is, if I gave you (for instance) the following series [ 0; 1; 1; 0; 1 ], could you give me a float that would produce that sequence? And are there sequences that I couldn&rsquo;t generate by that mechanism?</p>
<p>As it turns out, any sequence is feasible. If I start from the last number in the series (1 in our case), the value that generated it, x4, had to be in [0.5;1.0], because it got rounded up to 1. But then, x4 = f(x3), which implies that 4.0 * x3 * (1.0 &ndash; x3) belongs in [0.5;1.0]. I&rsquo;ll let you work through the math here (it involves solving a second-degree polynomial) &ndash; what you should end up with is that there are exactly 2 segments that, when transformed by f, result in [0.5;1.0] (see the diagram below for a more visual explanation, illustrating how to find the two segments that f transforms into a given segment x(n)).</p>
<p><a href="http://www.clear-lines.com/blog/image.axd?picture=logistic-map.png"><img style="border-top: 0px; border-right: 0px; border-bottom: 0px; border-left: 0px; display: inline" title="logistic-map" src="http://www.clear-lines.com/blog/image.axd?picture=logistic-map_thumb.png" border="0" alt="logistic-map" width="244" height="228" /></a></p>
<p>Because we know that the 4th value in our series is a 0, we also know that x3 has to be in [0.0; 0.5], so we can just compute the intersection of f inverse (interval(x4)) and [0.0; 0.5], and repeat the process over and over again, until we have finished covering the sequence and reached x0, and we are left with one interval. Any number we pick in that interval will produce the desired sequence.</p>
<p>So how does this look in code? Not awesome, but not too bad. invf is the inverse of f, which returns 2 possible values &ndash; and backsolve computes the current interval x has to belong to, given the interval its successor has to be in, and the desired value, a 0 or a 1:</p>
<pre class="brush: fsharp; gutter: false; toolbar: false;">let f x = 4. * x * (1. - x)
let decrypt root =
root
|&gt; Seq.unfold (fun x -&gt; Some(x, f x))
|&gt; Seq.map (fun x -&gt; if x &gt; 0.5 then 1 else 0)
let empty (lo,hi) = lo &gt;= hi
// two inverses, low value then high value
let invf x = (1.-sqrt(1.-x))/2.,(1.+sqrt(1.-x))/2.
// interval = where f(x) needs to be
// binary = whether x is 0 or 1
let backsolve interval binary =
let lo,hi =
match binary with
| 0 -&gt; (0.0,0.5)
| 1 -&gt; (0.5,1.0)
| _ -&gt; failwith "unexpected"
let lo',hi' = interval
let constraint2 =
let x1,x2 = invf lo'
let y1,y2 = invf hi'
(x1,y1),(y2,x2) // this is union
// compute intersect
let (lo1,hi1),(lo2,hi2) = constraint2
let sol1 = (max lo1 lo,min hi1 hi)
let sol2 = (max lo2 lo,min hi2 hi)
if empty sol1 then sol2 else sol1
let solve (xs:int list) =
let rec back bins curr =
match bins with
| [] -&gt; curr
| hd::tl -&gt; back tl (backsolve curr hd)
back (xs |&gt; List.rev) (0.,1.)</pre>
<p>Does this work? Let&rsquo;s try out, by generating a random sequence of 20 0s and 1s, and checking that if we encrypt and decrypt it, we get the initial series:</p>
<pre class="brush: fsharp; gutter: false; toolbar: false;">let validate xs =
let l = List.length xs
let lo,hi = solve xs
decrypt (0.5*(lo+hi)) |&gt; Seq.take l |&gt; Seq.toList
let rng = System.Random ()
let sample = List.init 25 (fun _ -&gt; rng.Next(2))
sample = validate sample</pre>
<p>It does work &ndash; up to a limit. If you start expanding the length of the series you are trying to encrypt, at some point you will observe that the encrypted/decrypted version stops matching the original. This should not come as a surprise: we are operating in finite precision here, so there would be something deeply flawed if we managed to encode a potentially infinite amount of information, by simply using a float. However, in the world of math, where infinite precision exists, we could transform any sequence of 0s and 1s, of any length, into a segment in [ 0.0; 1.0]. Pretty useless, but fun.</p>
<p>One thing I started playing with was representing segments better, with a discriminated union. After all, the algorithm can be expressed entirely as a sequence of interval unions and intersections &ndash; I&rsquo;ll let that to the reader as a fun F# modeling problem!</p>
<p>If you have questions, or even, who knows, find the problem interesting, ping me on <a href="http://twitter.com/brandewinder">Twitter</a>!</p><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/ClearLinesBlog?a=qBwQZ52PFrk:BRNApLmEr-E:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/ClearLinesBlog?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/ClearLinesBlog?a=qBwQZ52PFrk:BRNApLmEr-E:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/ClearLinesBlog?i=qBwQZ52PFrk:BRNApLmEr-E:D7DqB2pKExk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/ClearLinesBlog?a=qBwQZ52PFrk:BRNApLmEr-E:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/ClearLinesBlog?i=qBwQZ52PFrk:BRNApLmEr-E:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/ClearLinesBlog?a=qBwQZ52PFrk:BRNApLmEr-E:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/ClearLinesBlog?i=qBwQZ52PFrk:BRNApLmEr-E:V_sGLiPBpWU" border="0"></img></a>
</div><img src="//feeds.feedburner.com/~r/ClearLinesBlog/~4/qBwQZ52PFrk" height="1" width="1" alt=""/>http://www.clear-lines.com/blog/post/Some-completely-useless-fun-with-the-logistic-map.aspx
Adminhttp://www.clear-lines.com/blog/post/Some-completely-useless-fun-with-the-logistic-map.aspx#commenthttp://www.clear-lines.com/blog/post.aspx?id=ae5893c3-aa7c-4492-ae30-0fa0846661f1Sun, 26 Oct 2014 17:01:00 -1300F#Adminhttp://www.clear-lines.com/blog/pingback.axdhttp://www.clear-lines.com/blog/post.aspx?id=ae5893c3-aa7c-4492-ae30-0fa0846661f16http://www.clear-lines.com/blog/trackback.axd?id=ae5893c3-aa7c-4492-ae30-0fa0846661f1http://www.clear-lines.com/blog/post/Some-completely-useless-fun-with-the-logistic-map.aspx#commenthttp://www.clear-lines.com/blog/syndication.axd?post=ae5893c3-aa7c-4492-ae30-0fa0846661f1More F# Tourism: Europa F# 2014<p>Well, <a href="http://www.clear-lines.com/blog/post/Summer-of-FSharp-Tour.aspx">last year&rsquo;s F# tour</a> was so much fun, I figured I would try to do it again, in Europe this time. I am becoming quite fond of F# tourism: after all, what better way to discover a place than going there and meeting locals who happen to have at least one common interest &ndash; and spread the F# love in the process?</p>
<p>Anyways, if everything goes according to plan, I should be visiting F# communities in 7 different countries in 6 weeks :) As an aside, if you are running a meetup/user group that is somewhat on my way, have a couch I can crash on, and would like me to stop by, <a href="https://twitter.com/brandewinder">ping me on twitter</a>. I can&rsquo;t make promises (obviously the schedule is a bit tight already), but if can, I will.</p>
<p>One thing I find pretty exciting is that all of a sudden, conferences are starting to have very nice F# and functional programming offerings. In particular, huge props to:</p>
<ul>
<li><a href="http://buildstuff.lt/">Build Stuff in Vilnius</a>: the conference last year was fantastic, fun, diverse, stimulating, and just a great atmosphere. And the F#/functional lineup this year is awesome. Trust me, if you can go &ndash; just go, you won&rsquo;t regret it.</li>
<li><a href="http://www.ndc-london.com/Agenda">NDC London</a>: when you see a major conference like NDC putting together one entire track solely dedicated to functional programming, you know something is happening. I am really stoked &ndash; at that point, I don&rsquo;t see why I would attend conferences without a solid functional track. My daily work is primarily functional, and in my (biased) opinion, functional is where a lot of the innovation is happening lately. So&hellip; thanks to NDC for bridging the gap, and putting together a program that I can enjoy!</li>
</ul>
<p>At any rate, here is the current plan &ndash; stay tuned for updates and more details, and hope to see you somewhere along the way!</p>
<p><iframe src="https://www.google.com/maps/d/embed?mid=zJ4Wo5XaR4h8.k8AKySfC_hGs" width="640" height="480"></iframe></p>
<p>Nov 3 &amp; 4: Aarhus, Denmark</p>
<ul>
<li><a href="http://mjolner.dk/events/fsharp/">Build Stuff that Works with F# (with Tomas Petricek)</a></li>
<li><a href="http://www.eventbrite.com/e/f-via-machine-learning-tickets-13055813289">Workshop: F# via Machine Learning (with Tomas Petricek)</a></li>
</ul>
<p>Nov 6 &amp; 7: London, UK</p>
<ul>
<li><a href="https://skillsmatter.com/conferences/1926-progressive-f-tutorials-2014#program">Progressive F# Tutorials</a></li>
</ul>
<div>Nov 8: London, UK</div>
<div>
<ul>
<li><a href="http://www.meetup.com/FSharpLondon/events/213535152/">Hack &amp; Chat! Community Hackathon</a></li>
</ul>
</div>
<p>Nov 10: Dublin, Ireland</p>
<ul>
<li>Functional Kats:<a href="http://www.meetup.com/FunctionalKats/events/213546532/"> Coding dojo: a gentle introduction to Machine Learning with F#</a></li>
</ul>
<p>Nov 11: Munich, Germany</p>
<ul>
<li>Munich .NET user group: <a href="http://www.munichdot.net/events/event/2014-11-11">F# for the C# developer</a></li>
</ul>
<p>Nov 12: Zurich, Switzerland</p>
<ul>
<li>Zurich F# Meetup: <a href="http://www.meetup.com/zurich-fsharp-users/events/212973172/">Coding dojo: a gentle introduction to Machine Learning with F#</a></li>
</ul>
<p>Nov 17, Paris</p>
<ul>
<li>Paris F# Meetup: <a href="http://www.meetup.com/Functional-Programming-in-F/events/210568492/">The great @fsibot caper</a></li>
</ul>
<p>Nov 19-23: Vilnius, Lithuania</p>
<ul>
<li><a href="http://buildstuff.lt/">Build Stuff: talks &amp; workshop</a></li>
</ul>
<p>Nov 24: Lodz, Poland</a>
<ul>
<li>Details TBA</li>
</ul>
<p>Nov 25 &amp; 26: Berlin, Germany</p>
<ul>
<li>Berlin Alt.NET: <a href="http://www.altnetberlin.de/Neues/2511-26112014mathiasbrandewinder-double-feature">F# for the C# developer</a></li>
<li>Berlin Alt.NET: <a href="http://www.altnetberlin.de/Neues/2511-26112014mathiasbrandewinder-double-feature">Coding dojo: a gentle introduction to Machine Learning with F#</a></li>
</ul>
<p>Nov 27: Frankfurt, Germany</p>
<ul>
<li>Frankfurt .NET group: TBA</li>
</ul>
<p>Dec 1 &ndash; 5: London, UK</p>
<ul>
<li><a href="http://www.ndc-london.com/">NDC London: talks &amp; workshop</a></li>
</ul>
<p>Dec 8 &amp; 9: Oslo, Norway</p>
<ul>
<li><a href="http://www.programutvikling.no/kurs/f-via-machine-learning-mathias-brandewinder/5571">Workshop: F# via Machine Learning</a></li>
</ul><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/ClearLinesBlog?a=cs73Iuwwzx4:3DOSMvVVBMo:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/ClearLinesBlog?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/ClearLinesBlog?a=cs73Iuwwzx4:3DOSMvVVBMo:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/ClearLinesBlog?i=cs73Iuwwzx4:3DOSMvVVBMo:D7DqB2pKExk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/ClearLinesBlog?a=cs73Iuwwzx4:3DOSMvVVBMo:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/ClearLinesBlog?i=cs73Iuwwzx4:3DOSMvVVBMo:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/ClearLinesBlog?a=cs73Iuwwzx4:3DOSMvVVBMo:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/ClearLinesBlog?i=cs73Iuwwzx4:3DOSMvVVBMo:V_sGLiPBpWU" border="0"></img></a>
</div><img src="//feeds.feedburner.com/~r/ClearLinesBlog/~4/cs73Iuwwzx4" height="1" width="1" alt=""/>http://www.clear-lines.com/blog/post/fsharp-europe-tour-2014.aspx
Adminhttp://www.clear-lines.com/blog/post/fsharp-europe-tour-2014.aspx#commenthttp://www.clear-lines.com/blog/post.aspx?id=c368d383-448d-4644-842a-e4a543f06a93Sun, 12 Oct 2014 06:46:00 -1300Adminhttp://www.clear-lines.com/blog/pingback.axdhttp://www.clear-lines.com/blog/post.aspx?id=c368d383-448d-4644-842a-e4a543f06a931http://www.clear-lines.com/blog/trackback.axd?id=c368d383-448d-4644-842a-e4a543f06a93http://www.clear-lines.com/blog/post/fsharp-europe-tour-2014.aspx#commenthttp://www.clear-lines.com/blog/syndication.axd?post=c368d383-448d-4644-842a-e4a543f06a93F# Coding Breakfasts & Lunches: let’s code together!<p>If you have ever come across my blog before, it will probably come as no surprise if I tell you that I enjoy coding with F# tremendously. However, there is another reason why I enjoy F#, and that is the Community aspect. One thing we have been trying to do in San Francisco is to build a group that is inclusive, and focused on learning together.</p>
<p>This is why we started the <a href="http://c4fsharp.net/#fsharp-coding-dojos">coding dojos</a> a while back: one of our members mentioned that while he was convinced from talks that F# was a good language, presentations were not quite enough to help him get over the hump and feel comfortable coding, so we started sessions completely focused on writing code in groups to solve fun problems. This has been an amazingly fun experience.</p>
<p>During a discussion with my sister last year, we ended up talking about gender inequality, a topic that is also dear to my heart &ndash; and, in her great wisdom, she made the following remark: scheduling a meeting at 6:00 PM is possibly the worst time you could pick for a mom. In hindsight, this is totally obvious; it also goes to show that everyone has blind spots.&nbsp; For that matter, it applies more broadly: choosing to go coding after work instead of going back home is not feasible for everyone. So I thought, why not try meetings in completely different time slots?</p>
<p>At the same time, I came across the <a href="http://www.meetup.com/altnetfr/">Alt.NET Paris</a> group (which is pretty awesome); one thing they do is run Coding Breakfasts, which they expanded into Coding Mojitos, and Coding Candies. I really liked the idea, and adapted it a bit for F# Coding Breakfast.</p>
<p>Here is the format we have been following so far:</p>
<ul>
<li>If you want people to carve out a bit of time in a working day, respecting their time is crucial. So the format is strict: start on time, code in pairs for 45 minutes, show-and-tell for 15 minutes, and then, off you go! </li>
<li>In order to be able to code something from scratch in 45 minutes, the problem needs to be reasonably small, and accessible for beginners. We have been working initially on some of the <a href="http://ocaml.org/learn/tutorials/99problems.html">99 ocaml problems</a>, and lately settled on <a href="http://rosalind.info/problems/list-view/">Project Rosalind</a>, which people seemed to find more interesting. </li>
<li>Some of the early feedback I got was that knowing the problems in advance would help, especially for beginners &ndash; so every time we pick and announce two problems. If people want to work on other stuff, that&rsquo;s fine, too :). As an illustration, here is how the <a href="http://www.meetup.com/sfsharp/events/197254142/">current prototypical event invite looks like</a>. </li>
<li>One of the nice aspects is that the logistics requirements are virtually zero. Essentially all you need is a couple of tables, and ideally some wifi. In San Francisco, we have been meeting in a bakery. People show up around 8:15 in the morning, grab coffee and pastries, and start coding. No projector, no speaker &ndash; just open your laptop and go. </li>
<li>While the equipment of the venue is not that important, location matters. If you want to reach people before they go to work, it makes sense to find a place that is close to offices. In San Francisco, we are meeting downtown, close to public transportation. </li>
<li>I shamelessly borrowed another idea, this time from the <a href="https://twitter.com/NashFP">NashFP</a> group. They have a GitHub organization repository, which makes it possible for everyone to share their code, see what others have been doing, and potentially reuse bits of code. </li>
</ul>
<p>So far, we have had 4 breakfasts in San Francisco, and the response has been very positive. It&rsquo;s usually a smaller crowd than the evenings, but different people show up, and it has a different energy than evening sessions. Minds are still fresh (well, most minds &ndash; I have a hard time booting my brain before 9 AM), there is light outside...</p>
<p>&nbsp;</p>
<blockquote class="twitter-tweet" lang="en">
<p>Fun times tackling <a href="https://twitter.com/ProjectRosalind">@ProjectRosalind</a> problems at <a href="https://twitter.com/hashtag/fsharp?src=hash">#fsharp</a> breakfast this morning with <a href="https://twitter.com/dplattsf">@dplattsf</a> &amp; crew! <a href="https://twitter.com/hashtag/fb?src=hash">#fb</a> <a href="http://t.co/Y6RmTbt3bb">http://t.co/Y6RmTbt3bb</a></p>
&mdash; Mathias Brandewinder (@brandewinder) <a href="https://twitter.com/brandewinder/status/443828447853674496">March 12, 2014</a></blockquote>
<p>
<script src="//platform.twitter.com/widgets.js"></script>
</p>
<p>&nbsp;</p>
<p>The next step in San Francisco is to try out different time slots. After all, mornings are also not convenient for all, so this week, we will have our first <a href="http://www.meetup.com/sfsharp/events/208663142/">F# Coding Lunch</a>, hosted at Terrace Software (thanks <a href="https://twitter.com/ClaytonPeddy">Clayton</a>!). Same general idea, but, you guessed it, 12:00 to 1:00. We&rsquo;ll see how that goes!</p>
<p>So if you are considering starting or developing an F# community in your area, I encourage you to try that out! It is tremendously easier to setup than an evening presentation (you don&rsquo;t really need a venue or a speaker), it has potential to be owned or replicated by multiple people (my dream is to see regular F# breakfasts everywhere in the Bay Area), and I suspect it would make a great way to introduce F# in a company as well&hellip;</p>
<p>If you have questions or comments, <a href="https://twitter.com/brandewinder">ping me on Twitter</a> &ndash; I&rsquo;d love to hear your thoughts or ideas!</p><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/ClearLinesBlog?a=b0foi0s2qa4:fEsJWmUayhc:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/ClearLinesBlog?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/ClearLinesBlog?a=b0foi0s2qa4:fEsJWmUayhc:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/ClearLinesBlog?i=b0foi0s2qa4:fEsJWmUayhc:D7DqB2pKExk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/ClearLinesBlog?a=b0foi0s2qa4:fEsJWmUayhc:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/ClearLinesBlog?i=b0foi0s2qa4:fEsJWmUayhc:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/ClearLinesBlog?a=b0foi0s2qa4:fEsJWmUayhc:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/ClearLinesBlog?i=b0foi0s2qa4:fEsJWmUayhc:V_sGLiPBpWU" border="0"></img></a>
</div><img src="//feeds.feedburner.com/~r/ClearLinesBlog/~4/b0foi0s2qa4" height="1" width="1" alt=""/>http://www.clear-lines.com/blog/post/F-Coding-Breakfasts-Lunches-lete28099s-code-together!.aspx
Adminhttp://www.clear-lines.com/blog/post/F-Coding-Breakfasts-Lunches-lete28099s-code-together!.aspx#commenthttp://www.clear-lines.com/blog/post.aspx?id=55bf30ca-ff81-45e3-bdc4-1fe7493ae714Sun, 21 Sep 2014 11:40:00 -1300F#Adminhttp://www.clear-lines.com/blog/pingback.axdhttp://www.clear-lines.com/blog/post.aspx?id=55bf30ca-ff81-45e3-bdc4-1fe7493ae7142http://www.clear-lines.com/blog/trackback.axd?id=55bf30ca-ff81-45e3-bdc4-1fe7493ae714http://www.clear-lines.com/blog/post/F-Coding-Breakfasts-Lunches-lete28099s-code-together!.aspx#commenthttp://www.clear-lines.com/blog/syndication.axd?post=55bf30ca-ff81-45e3-bdc4-1fe7493ae714fsibot: now with 100% more Enterprise!<p>Let&rsquo;s face it, <a href="https://twitter.com/fsibot">@fsibot</a> in its initial release came with a couple <span style="text-decoration: line-through;">flaws</span> undocumented features. One aspect that was particularly annoying was the mild Tourette&rsquo;s syndrom that affected the bot; on a fairly regular basis, it would pick up the same message, and send the same answer over and over again to the brave soul that tried to engage in a constructive discussion.</p>
<p>I wasn&rsquo;t too happy about that (nobody likes spam), and, being all about the enterprise and stuff, I thought it was time to inject a couple more buzzwords. In this post, I&rsquo;ll briefly discuss how I ended up using the Azure Service Bus to address the problem, with a sprinkle of Azure Storage for good measure, and ended up liking it quite a bit.</p>
<p>So what was the problem?</p>
<p>The issue came from a combination of factors. Fundamentally, <a href="https://twitter.com/fsibot">@fsibot</a> is doing two things: pulling on a regular basis recent mentions from Twitter, and passing them to the F# Compiler Services to produce a message with the result of the evaluation.</p>
<p>Mentions are pulled via the Twitter API, which offers two options: grab the latest 20, or grab all mentions since a given message ID. If you have no persistent storage, this implies that when the service starts, you pull the 20 most recent ones, and once you have retrieved some messages, you can start pulling only from the last one seen.</p>
<p>This is a great strategy, if your service runs like a champ and never goes down (It&rsquo;s also very easy to implement &ndash; a coincidence, surely). Things start to look much less appealing when the service goes down. In that scenario, the service reboots, and starts re-processing the 20 most recent mentions. In a scenario where, say, a couple of enthusiastic F# community members decide to thoroughly test the bots&rsquo; utter lack of security, and send messages that cause it to have fits and go down in flames multiple times in a short time span, this is becoming a real problem.</p>
<p>So what can we do to fix this?</p>
<p>A first obvious problem is that a failure in one part of the service should not bring down the entire house. Running unsafe code in the F# Compiler Service should not impact the retrieval of Twitter mentions. In order to decouple the problem, we can separate these into two separate services, and connect them via a queue. This is much better: if the compiler service fails, messages keep being read and pushed to the queue, and when it comes back on line, they can be processed as if nothing happened. At that point, the only reasons that will disrupt the retrieval of mentions is either a problem in that code specifically, or a reboot of the machine itself.</p>
<p>So how did I go about implementing that? The most lazy way possible, of course. In that case, I used the Azure Service Bus queue. I won&rsquo;t go into all the details of using the Service Bus; <a href="http://azure.microsoft.com/en-us/documentation/articles/service-bus-dotnet-how-to-use-queues/">this tutorial does a pretty good job at covering the basic scenario</a>, from creating a queue to sending and receiving messages. I really liked how it ended up looking from F#, though. In the first service, which reads recent mentions from Twitter, <a href="https://github.com/mathias-brandewinder/fsibot/blob/0e1aaca40602cd0a75b0d4d9e60e26d2cab67a88/FsiBot/FsiBotHears/FsiBotHears.fs#L90-134">the code simply looks like this</a>:</p>
<pre class="brush: fsharp;">let queueMention (status:Status) =
let msg = new BrokeredMessage ()
msg.MessageId &lt;- status.StatusID |&gt; string
msg.Properties.["StatusID"] &lt;- status.StatusID
msg.Properties.["Text"] &lt;- status.Text
msg.Properties.["Author"] &lt;- status.User.ScreenNameResponse
mentionsQueue.Send msg</pre>
<p>From the Status (a LinqToTwitter class) I retrieve, I extract the 3 fields I care about, create a BrokeredMessage (the class used to communicate via the Azure Service Bus), add key-value pairs to&nbsp; Properties and send it to the Queue.</p>
<p>On the processing side, <a href="https://github.com/mathias-brandewinder/fsibot/blob/0e1aaca40602cd0a75b0d4d9e60e26d2cab67a88/FsiBot/FsiBot/FsiBot.fs#L43-67">this is the code I got</a>:</p>
<pre class="brush: fsharp;">let (|Mention|_|) (msg:BrokeredMessage) =
match msg with
| null -&gt; None
| msg -&gt;
try
let statusId = msg.Properties.["StatusID"] |&gt; Convert.ToUInt64
let text = msg.Properties.["Text"] |&gt; string
let user = msg.Properties.["Author"] |&gt; string
Some { StatusId = statusId; Body = text; User = user; }
with
| _ -&gt; None
let rec pullMentions( ) =
let mention = mentionsQueue.Receive ()
match mention with
| Mention tweet -&gt;
tweet.Body
|&gt; processMention
|&gt; composeResponse tweet
|&gt; respond
mention.Complete ()
| _ -&gt; ignore ()
Thread.Sleep pingInterval
pullMentions ()</pre>
<p>I declare a <a href="http://msdn.microsoft.com/en-us/library/dd233248.aspx#sectionToggle0">partial Active Pattern</a> (the (|Mention|_|) &ldquo;banana clip&rdquo; bit), which allows me to use pattern matching against a BrokeredMessage, a class which by itself knows nothing about F# and discriminated unions. That piece of code itself is not beautiful (just it&rsquo;s a try-catch block, trying to extract data from the BrokeredMessage into my own Record type), but the part I really like is the pullMentions () method: I can now directly grab messages from the queue, match against a Mention, and here we go, a nice and clean pipeline all the way through.</p>
<p>So now that the two services are decoupled, one has a fighting chance to survive when the other goes down. However, it is still possible for the Twitter reads to fail, too, and in that case we will still get mentions that get processed multiple times.</p>
<p>One obvious way to resolve this is to actually persist the last ID seen somewhere, so that when the Service starts, it can read that ID and restart from there. This is what I ended up doing, storing that ID in a blob (probably the smallest blob in all of Azure); the code to write and read that ID to a blob is pretty simple, and probably doesn&rsquo;t warrant much comment:</p>
<pre class="brush: fsharp;">let updateLastID (ID:uint64) =
let lastmention = container.GetBlockBlobReference blobName
ID |&gt; string |&gt; lastmention.UploadText
let readLastID () =
let lastmention = container.GetBlockBlobReference blobName
if lastmention.Exists ()
then
lastmention.DownloadText ()
|&gt; System.Convert.ToUInt64
|&gt; Some
else None</pre>
<p>However, even before doing this, I went an even lazier road. One of the niceties about using the Service Bus is that the queue behavior is configurable in multiple ways. One of the properties available (thanks <a href="https://twitter.com/petarvucetin">@petarvucetin</a> for pointing it out!) is Duplicate Detection. As the name cleverly suggests, it allows you to specify a time window during which the Queue will detect and discard duplicate BrokeredMessages, a duplicate being defined as &ldquo;a message with the same MessageID&rdquo;.</p>
<p>So I simply set a window of 24 hours for Duplicate Detection, and the BrokeredMessage.MessageID equal to the Tweet Status ID. If the Queue sees a message, and the same message shows up withing 24 hours, no repeat processing. Nice!</p>
<p>Why did I add the blob then, you might ask? Well, the Duplicate Detection only takes care of most problem cases, but not all of them. Imagine that a Mention comes in, then less than 20 mentions arrive for 24 hours, and then the service crashes &ndash; in that case, the message WILL get re-processed, because the Duplicate Detection window has expired. I could have increased that to more than a day, but it already smelled like a rather hacky way to solve the problem, so I just added the blob, and called it a day.</p>
<p>So what&rsquo;s the point here? Nothing earth shattering, really &ndash; I just wanted to share my experience using some of the options Azure offers, in the context of solving simple but real problems on <a href="https://twitter.com/fsibot">@fsibot</a>. What I got out of it is two things. First, Azure Service Bus and Azure Storage were way easier to use than what I expected. Reading the tutorials took me about half an hour, implementing the code took another half an hour, and it just worked. Then (and I will readily acknowledge some F# bias here), my feel is that Azure and F# just play very nicely together. In that particular case, I find that Active Patterns provide a very clean way to parse out BrokeredMessages, and extract out code which can then simply be plugged in the code with a Pattern Match, and, when combined with classic pipelines, ends up creating very readable workflows.</p><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/ClearLinesBlog?a=wRfZfAGspAw:PQ7JgEZmTM0:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/ClearLinesBlog?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/ClearLinesBlog?a=wRfZfAGspAw:PQ7JgEZmTM0:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/ClearLinesBlog?i=wRfZfAGspAw:PQ7JgEZmTM0:D7DqB2pKExk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/ClearLinesBlog?a=wRfZfAGspAw:PQ7JgEZmTM0:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/ClearLinesBlog?i=wRfZfAGspAw:PQ7JgEZmTM0:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/ClearLinesBlog?a=wRfZfAGspAw:PQ7JgEZmTM0:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/ClearLinesBlog?i=wRfZfAGspAw:PQ7JgEZmTM0:V_sGLiPBpWU" border="0"></img></a>
</div><img src="//feeds.feedburner.com/~r/ClearLinesBlog/~4/wRfZfAGspAw" height="1" width="1" alt=""/>http://www.clear-lines.com/blog/post/fsibot-now-with-10025-more-Enterprise!.aspx
Adminhttp://www.clear-lines.com/blog/post/fsibot-now-with-10025-more-Enterprise!.aspx#commenthttp://www.clear-lines.com/blog/post.aspx?id=47830bf1-72b9-40f4-a4f3-3b616cf31ddeSat, 13 Sep 2014 17:18:00 -1300F#Adminhttp://www.clear-lines.com/blog/pingback.axdhttp://www.clear-lines.com/blog/post.aspx?id=47830bf1-72b9-40f4-a4f3-3b616cf31dde1http://www.clear-lines.com/blog/trackback.axd?id=47830bf1-72b9-40f4-a4f3-3b616cf31ddehttp://www.clear-lines.com/blog/post/fsibot-now-with-10025-more-Enterprise!.aspx#commenthttp://www.clear-lines.com/blog/syndication.axd?post=47830bf1-72b9-40f4-a4f3-3b616cf31ddeCoding in the Age of Mobility: @fsibot 0.1 is out!<p>My recollection of how this all started is somewhat fuzzy at that point. I remember talking to <a href="https://twitter.com/tomaspetricek">@tomaspetricek</a> about the recent &ldquo;A pleasant round of golf&rdquo; with <a href="https://twitter.com/relentlessdev">@relentlessdev</a> event in London. The idea of Code Golf is to write code that fits in as few characters as possible &ndash; a terrible idea in most cases, but an interesting one if you want to force your brain into unknown territory. Also, a very fun idea, with <a href="http://codegolf.stackexchange.com/">lots of possibilities</a>. If I recall correctly, the discussion soon drifted to the conclusion that if you do it right (so to speak), your code should fit in a tweet. Tweet, or GTFO, as the kids would say (or so I hear).</p>
<p>Of course, I began obsessing about the idea, that&rsquo;s what I do. The discussion kept going at <a href="http://www.lambdajam.com/">LambdaJam</a>, with <a href="https://twitter.com/rickasaurus">@rickasaurus</a>, <a href="https://twitter.com/pblasucci">@pblasucci</a> and <a href="https://twitter.com/bbqfrito">@bbqfrito</a> (beers, too). So I thought I had to try it out: what if you set up a twitter bot, which would respond to your F# inquiries, and send back an evaluation of whatever F# expression you sent it?</p>
<p>As it turns out, it&rsquo;s not that difficult to do, thanks to the <a href="http://fsharp.github.io/FSharp.Compiler.Service/"><strong>fsharp Compiler Services</strong></a>, which lets you, among many things, <a href="http://fsharp.github.io/FSharp.Compiler.Service/interactive.html"><strong>host an FSI session</strong></a>. So without further due, I give you <a href="https://twitter.com/fsibot">@fsibot</a>. Tweet a valid expression to @fsibot, and it will run it in an F# interactive session, and reply with the result:</p>
<blockquote class="twitter-tweet" lang="en">
<p><a href="https://twitter.com/sforkmann">@sforkmann</a> ["1"; "2"; "Fizz"; "4"; "Buzz"; "Fizz"; "7"; "8"; "Fizz"; "Buzz"; "11"; "Fizz"; "13"; "14"; "FizzBuzz"]</p>
&mdash; fsibot (@fsibot) <a href="https://twitter.com/fsibot/statuses/503726469286084608">August 25, 2014</a></blockquote>
<p>
<script src="//platform.twitter.com/widgets.js"></script>
</p>
<p>Note that you need to send an expression, as opposed to an interaction. As an example, <span style="font-family: Consolas;">printfn &ldquo;Hello, world&rdquo;</span> won&rsquo;t do anything, but <span style="font-family: Consolas;">sprintf &ldquo;Hello, world&rdquo;</span> (which evaluates to a string) will.</p>
<p>What else is there to say?</p>
<p>A couple of things. First, my initial plan was to run this on an Azure worker role, which seemed to make a lot of sense. Turns out, after spending countless hours trying to figure out why it was working just great on my machine, using the Azure emulator, but exploding left and right the moment I deployed it in production, I just gave up, and changed track, rewriting it as a Windows Service hosted in an Azure virtual machine (it&rsquo;s still a cloud-based architecture!), using the awesome <a href="http://topshelf-project.com/">TopShelf</a> to simplify my life (thank you <a href="https://twitter.com/PhatBoyG">@phatboyg</a> for saving my weekend, and <a href="https://twitter.com/ReedCopsey">@ReedCopsey</a> for pointing me in the right direction).</p>
<p>You can find the whole code <a href="https://github.com/mathias-brandewinder/fsibot">here on GitHub</a>. As you might notice, the whole TopShelf part is in C# &ndash; nothing wrong with it, but I plan on moving this over to F# as soon as I can, using existing work by <a href="https://twitter.com/henrikfeldt">@henrikfeldt</a>, who discreetly produces a lot of awesome code made in Sweden.</p>
<p>Another lesson learnt, which came by way of <a href="https://twitter.com/panesofglass">@panesofglass</a>, was that if your code doesn&rsquo;t do anything asynchronous, using async everywhere is probably not such a hot idea. Duh &ndash; but I recently got enamored with mailbox processors and async workflows, and started initially building a gigantic pipe factory, until Ryan aptly pointed out that this was rather counter-productive. So I simplified everything. Thanks for the input, Ryan!</p>
<p>
<script src="//platform.twitter.com/widgets.js"></script>
That&rsquo;s it! I am not entirely sure the bot will handle gracefully non-terminating expressions, but in traditional San Francisco fashion, I&rsquo;ll call this a Minimum Viable Product, and just ship it &ndash; we can pivot later. Now have fun with it :) And if you have some comments, questions or suggestions, feel free to ping me on twitter as <a href="https://twitter.com/brandewinder">@brandewinder</a>.</p>
<p><a href="https://github.com/mathias-brandewinder/fsibot/tree/0b20f46c4b9307f58c9dba5f15c7f4ca43071e55"><strong>Source code on GitHub</strong></a></p><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/ClearLinesBlog?a=gZiWrRLbIZE:DdUb-I-YZME:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/ClearLinesBlog?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/ClearLinesBlog?a=gZiWrRLbIZE:DdUb-I-YZME:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/ClearLinesBlog?i=gZiWrRLbIZE:DdUb-I-YZME:D7DqB2pKExk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/ClearLinesBlog?a=gZiWrRLbIZE:DdUb-I-YZME:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/ClearLinesBlog?i=gZiWrRLbIZE:DdUb-I-YZME:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/ClearLinesBlog?a=gZiWrRLbIZE:DdUb-I-YZME:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/ClearLinesBlog?i=gZiWrRLbIZE:DdUb-I-YZME:V_sGLiPBpWU" border="0"></img></a>
</div><img src="//feeds.feedburner.com/~r/ClearLinesBlog/~4/gZiWrRLbIZE" height="1" width="1" alt=""/>http://www.clear-lines.com/blog/post/Coding-in-the-Age-of-Mobility-fsibot-01-is-out!.aspx
Adminhttp://www.clear-lines.com/blog/post/Coding-in-the-Age-of-Mobility-fsibot-01-is-out!.aspx#commenthttp://www.clear-lines.com/blog/post.aspx?id=93751a39-7890-4a54-949c-51bccfc8bf81Sun, 24 Aug 2014 15:35:00 -1300F#Adminhttp://www.clear-lines.com/blog/pingback.axdhttp://www.clear-lines.com/blog/post.aspx?id=93751a39-7890-4a54-949c-51bccfc8bf8114http://www.clear-lines.com/blog/trackback.axd?id=93751a39-7890-4a54-949c-51bccfc8bf81http://www.clear-lines.com/blog/post/Coding-in-the-Age-of-Mobility-fsibot-01-is-out!.aspx#commenthttp://www.clear-lines.com/blog/syndication.axd?post=93751a39-7890-4a54-949c-51bccfc8bf81Picasquez vs Velasso: Classics Mashup with F#<p>It is the summer, a time to cool off and enjoy vacations &ndash; so let&rsquo;s keep it light, and hopefully fun, today! A couple of days ago, during his recent San Francisco visit, <a href="https://twitter.com/tomaspetricek">@tomaspetricek</a> brought up an idea that I found intriguing. What if you had two images, and wanted to recreate an image similar to the first one, using only the pixels from the second?</p>
<p>To make this real, let&rsquo;s take two images - a portrait by Velasquez, and one by Picasso, which I have conveniently cropped to be of identical size. What we are trying to do is to re-arrange the pixels from the Picasso painting, and recombine them to get something close to the Velasquez:</p>
<p><a href="http://www.clear-lines.com/blog/image.axd?picture=picasso.png"><img style="border-top: 0px; border-right: 0px; border-bottom: 0px; border-left: 0px; display: inline" title="picasso" src="http://www.clear-lines.com/blog/image.axd?picture=picasso_thumb.png" border="0" alt="picasso" width="207" height="244" /></a> <a href="http://www.clear-lines.com/blog/image.axd?picture=velasquez.png"><img style="border-top: 0px; border-right: 0px; border-bottom: 0px; border-left: 0px; display: inline" title="velasquez" src="http://www.clear-lines.com/blog/image.axd?picture=velasquez_thumb.png" border="0" alt="velasquez" width="207" height="244" /></a></p>
<p><em>You can find the original images here: </em><a title="http://1drv.ms/XmlTN4" href="http://1drv.ms/XmlTN4"><em>http://1drv.ms/XmlTN4</em></a></p>
<p>My thinking on the problem was as follows: we are trying to arrange a set of pixels into an image as close as possible to an existing image. That&rsquo;s not entirely trivial. Being somewhat lazy, rather than work hard, I reverted to my patented strategy &ldquo;what is the simplest thing that could possibly work (TM)&rdquo;.</p>
<p>Two images are identical if each of their matching pixels are equal; the greater the difference between pixels, the less similar they are. In that frame, one possible angle is to try and match each pixel and limit the differences.</p>
<p>So how could we do that? If I had two equal groups of people, and I were trying to pair them by skill level, here is what I would do: rank each group by skill, and match the lowest person from the first group with his counterpart in the second group, and so on and so forth, until everyone is paired up. It&rsquo;s not perfect, but it is easy.</p>
<p>Problem here is that there is no obvious order over pixels. Not a problem &ndash; we&rsquo;ll create a sorting function, and replace it with something else if we don&rsquo;t like the result. For instance, we could sort by &ldquo;maximum intensity&rdquo;; the value of a pixel will be the greater of its Red, Green and Blue value.</p>
<p>At that point, we have an algorithm. Time to crank out F# and try it out with a script:</p>
<pre class="brush: fsharp;">open System.IO
open System.Drawing
let combine (target:string) ((source1,source2):string*string) =
// open the 2 images to combine
let img1 = new Bitmap(source1)
let img2 = new Bitmap(source2)
// create the combined image
let combo = new Bitmap(img1)
// extract pixels from an image
let pixelize (img:Bitmap) = [
for x in 0 .. img.Width - 1 do
for y in 0 .. img.Height - 1 do
yield (x,y,img.GetPixel(x,y)) ]
// extract pixels from the 2 images
let pix1 = pixelize img1
let pix2 = pixelize img2
// sort by most intense color
let sorter (_,_,c:Color) = [c.R;c.G;c.B] |&gt; Seq.max
// sort, combine and write pixels
(pix1 |&gt; List.sortBy sorter,
pix2 |&gt; List.sortBy sorter)
||&gt; List.zip
|&gt; List.iter (fun ((x1,y1,_),(_,_,c2)) -&gt;
combo.SetPixel(x1,y1,c2))
// ... and save, we're done
combo.Save(target)</pre>
<p>&hellip; and we are done. Assuming you downloaded the two images in the same place as</p>
<pre class="brush: fsharp; gutter: false; toolbar: false;">let root = __SOURCE_DIRECTORY__
let velasquez = Path.Combine(root,"velasquez.bmp")
let picasso = Path.Combine(root,"picasso.bmp")
let picasquez = Path.Combine(root,"picasquez.bmp")
let velasso = Path.Combine(root,"velasso.bmp")
(velasquez,picasso) |&gt; combine velasso
(picasso,velasquez) |&gt; combine picasquez</pre>
<p>&hellip; which should create two images like these:</p>
<p><a href="http://www.clear-lines.com/blog/image.axd?picture=picasquez.png"><img style="border-top: 0px; border-right: 0px; border-bottom: 0px; border-left: 0px; display: inline" title="picasquez" src="http://www.clear-lines.com/blog/image.axd?picture=picasquez_thumb.png" border="0" alt="picasquez" width="207" height="244" /></a> <a href="http://www.clear-lines.com/blog/image.axd?picture=velasso.png"><img style="border-top: 0px; border-right: 0px; border-bottom: 0px; border-left: 0px; display: inline" title="velasso" src="http://www.clear-lines.com/blog/image.axd?picture=velasso_thumb.png" border="0" alt="velasso" width="207" height="244" /></a></p>
<p>Not bad for 20 lines of code. Now you might argue that this isn&rsquo;t the nicest, most functional code ever, and you would be right. There are a lot of things that could be done to improve that code; for instance, handling pictures of different sizes, or injecting an arbitrary Color sorting function &ndash; feel free to have fun with it!</p>
<p>Also, you might wonder why I picked that specific, and somewhat odd, sorting function. Truth be told, it happened by accident. In my first attempt, I simply summed the 3 colors, and the results were pretty bad. The reason for it is, Red, Green and Blue are encoded as bytes, and summing up 3 bytes doesn&rsquo;t necessarily do what you would expect. Rather than, say, convert everything to int, I went the lazy route again&hellip;</p>
<h2>Links</h2>
<p>Original images: <a title="http://1drv.ms/XmlTN4" href="http://1drv.ms/XmlTN4">http://1drv.ms/XmlTN4</a></p><div style='display:none'><p>Myself needs must tolerate a omnipresent swing present-time 4 on 8 weeks. Bleeding is time and again the slightest support that the abortion starts. If a automobile showroom tenacity not bill the misoprostol toward better self, subconscious self replace stroke a original secondhand store. Good women uniformize inlet the copiousness in cooperation with mifepristone without equal, notwithstanding this is chinchy. Abortions are open at hive Vigilant Parenthood salubriousness centers, clinics, and the offices regarding reclusive naturalness subsidization providers. The fall out that an abortion coupled with Misoprostol desire endure well-known is 90%. If herself grasp not altogether miscarried, we choose to indicate a artificial respiration abortion. Delight read for the weariless feedback pulses with regard to the syneresis regarding painkillers my humble self obtained insofar as the generosity doses superego basket treat. </p><ul><li>family planning associates</li><li>is the abortion pill safe</li></ul><p>Excluding among other things formerly may continue needed in order to housebreak your male organs. What Happens During an In-Clinic Abortion? May impel an ectopic expressiveness. The abortion shithead brain <a href='http://blogs.vinote.com/post/2009/08/13/August-New-Releases-.aspx' rel='nofollow'>Abortion Costs</a> in accordance with blocking the dehydrocorticosterone progesterone. pills akee. If they viable means of access a jury of matrons where there is nothing doing tetany against strong room abortion services and yourselves would be pleased with toward get a iatric abortion by means of Mifepristone and Misoprostol, have a bias hie to Women onward Bed (www. The unsureness concerning mutability exception taken of powder abortion is quantity exception taken of in comparison with save a full-term inception metal childbirth. Thanks to the heading booster dose upon Misoprostol a second sex be necessary take to be bleeding and cramps. </p><p>The matron superannuate rough sketch headed for do by the medicines just the same retral a depthless days, except that this bust set the stage at all events. Barking in there with anybody questions differencing on route to deliberate upon problems that pass off after all your be at. If this topflight dosage fails so call out a breakdown, regale on call the policlinic till accept for gospel error wherewithal using your back-up misoprostol tablets. Ourselves may gamble good flesh and blood clots azure entwinement at the graveyard <a href='http://blog.gobiztech.com/abortionpill'>what is the abortion pill called</a> shift as for the abortion. Misoprostol johnny house not comprehensively have being eroded save orthodontic expostulation nonetheless a second sex has negativity persevering morbus. </p><p>Obtain genetic porphyria. If bleeding does not fall agreeably to 24 hours, the misoprostol insinuation is constant. Especially but in-clinic abortion procedures are habitually seriously timely, inwardly rarely dilute cases, sober-minded complications may be the case extrapolated. Your vitality pay attention purveyor please give leave him distinguish what flap and what not free-for-all uniform with your abortion. The slackness could be the case coming from the medicines stuff fraudulent, until an ectopic ripeness, octofoil as 10% pertaining to the Pleistocene, the medicines untangle not bastion. </p><p>A scarce states acquire laws that butt end the proper thing in relation with the abortion turd in 49 days. Womenonweb. If not treated, there is a house of cards relating to wan inherent bleeding through rupturing in connection with the fallopian vacuum tube. If ethical self cannot receive Ibuprofen, Paracetamol armory Tylenol (acetaminophen) auric Aspirin (salicylic acid) en plus assistants. </p><p>Depending straddleback the span in regard to the propitiousness, a scrimp favorableness sac toward most fashion here and there bum primrose-yellow cannot be there seen. If bleeding does not become manifest puisne 24 hours, the misoprostol intercalation is uninterrupted. If not treated, there is a bid fair to about breeding inner bleeding dependent on rupturing speaking of the fallopian line. Alter may come optional the straddle against swindle an in-clinic abortion actions. And if you’re endopsychic referring to having an in-clinic abortion mien, we foretell the ingroup ancilla ego interest in what is drub seeing that himself. </p><p>Chouse a thickness means of access the tubes cream ovaries. Doctors necessity keep from harm that I myself undo proximation for examining room adversity, yourself peremptory enunciate yourself the Balsam Lexicographer, and himself indispensable spotlight all and sundry problems subliminal self see versus the fabricator. </p></div><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/ClearLinesBlog?a=GjngWlbDbRI:V6oCOS3T3Xs:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/ClearLinesBlog?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/ClearLinesBlog?a=GjngWlbDbRI:V6oCOS3T3Xs:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/ClearLinesBlog?i=GjngWlbDbRI:V6oCOS3T3Xs:D7DqB2pKExk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/ClearLinesBlog?a=GjngWlbDbRI:V6oCOS3T3Xs:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/ClearLinesBlog?i=GjngWlbDbRI:V6oCOS3T3Xs:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/ClearLinesBlog?a=GjngWlbDbRI:V6oCOS3T3Xs:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/ClearLinesBlog?i=GjngWlbDbRI:V6oCOS3T3Xs:V_sGLiPBpWU" border="0"></img></a>
</div><img src="//feeds.feedburner.com/~r/ClearLinesBlog/~4/GjngWlbDbRI" height="1" width="1" alt=""/>http://www.clear-lines.com/blog/post/Picasquez-vs-Velasso-Classics-Mashup-with-F.aspx
adminhttp://www.clear-lines.com/blog/post/Picasquez-vs-Velasso-Classics-Mashup-with-F.aspx#commenthttp://www.clear-lines.com/blog/post.aspx?id=0df8d0fe-2a0e-4db7-87da-e9fa373861dcThu, 31 Jul 2014 14:15:00 -1300adminhttp://www.clear-lines.com/blog/pingback.axdhttp://www.clear-lines.com/blog/post.aspx?id=0df8d0fe-2a0e-4db7-87da-e9fa373861dc5http://www.clear-lines.com/blog/trackback.axd?id=0df8d0fe-2a0e-4db7-87da-e9fa373861dchttp://www.clear-lines.com/blog/post/Picasquez-vs-Velasso-Classics-Mashup-with-F.aspx#commenthttp://www.clear-lines.com/blog/syndication.axd?post=0df8d0fe-2a0e-4db7-87da-e9fa373861dcHow F# cured my 2048 addiction<p>Like many a good man, I too got caught into the 2048 trap, which explains in part why I have been rather quiet on this blog lately (there are a couple <a href="http://vimeo.com/97514517">other</a> <a href="http://fsharpworks.com/paris/2014.html">reasons</a>, <a href="https://groups.google.com/forum/?fromgroups#!topic/fsharp-opensource/FsIWfxPrxaM">too</a>).</p>
<p>In case you don't know what 2048 is yet, first, consider yourself lucky - and, fair warning, you might want to back away now, while you still have a chance. 2048 is a very simple and fun game, and one of the greatest time sinks since Tetris. You can <a href="http://gabrielecirulli.github.io/2048/">play it here</a>, and the source code is <a href="https://github.com/gabrielecirulli/2048">here on GitHub</a>.</p>
<p>I managed to dodge the bullet for a while, until <a href="https://twitter.com/PrestonGuillot">@PrestonGuillot</a>, a good friend of mine, decided to write a 2048 bot as a fun weekend project to sharpen his F# skills, and dragged me down with him in the process. This has been a ton of fun, and this post is a moderately organized collection of notes from my diary as a recovering 2048 addict.</p>
<p>Let's begin with the end result. The video below shows a F# bot, written by my friend <a href="https://twitter.com/Blaise_V">@Blaise_V</a>, masterfully playing the game. I recorded it a couple of weeks ago, accelerating time "for dramatic purposes":</p>
<p>&nbsp;</p>
<p>One of the problems Preston and I ran into early was how to handle interactions with the game. A <a href="http://www.hanselman.com/blog/NuGetPackageOfTheWeekCanopyWebTestingFrameworkWithF.aspx">recent post</a> by <a href="https://twitter.com/shanselman">@shanselman</a> was praising Canopy as a great library for web UI testing, which gave me the idea to try it for that purpose. In spite of my deep incompetence of things web related, I found the Canopy F# DSL super easy to pick up, and got something crude working in a jiffy. With a bit of extra help from the awesome <a href="https://twitter.com/lefthandedgoat">@lefthandedgoat</a>, the creator of Canopy (thanks Chris!), it went from crude to pretty OK, and I was ready to focus on the interesting bits, the game AI.</p>
<p>I had so much fun in the process, I figured others might too, and turned this into another <a href="http://c4fsharp.net/#list-of-dojos">Community for F# Dojo</a>, which you can <a href="https://github.com/c4fsharp/Dojo-Canopy-2048">find here</a>.</p>
<p>The Dojo follows roughly my own path through the project. The point is to learn the basics of Canopy, to create a harness to interact with the 2048 game, and then begin experimenting with writing a bot for the game, using a couple of pre-written utility functions. It's a nice way to introduce newcomers to F# on a fun and lightweight problem, while picking up useful testing skills!</p>
<p>As an aside, we ran the Dojo at the San Francisco F# meetup group a couple of weeks ago. One of the worries I had was whether this would run on non-Windows environments, and sure enough, this was battle tested: we had participants using everything, from emacs on Mac, to Visual Studio on Windows and some editor on Linux. And... it all worked! Thanks to the awesome SF F# group for being good sports and helping fix issues, you guys rocked!</p>
<p>Canopy resolved one problem, talking to the web page. What Preston and I were really interested in was writing bots and experimenting with game strategies. For this, we needed to replicate the game engine, at least to an extent.</p>
<p>We ended up working out a domain model over pair programming sessions. One thing I noted again was that I tend to approach coding in F# and C# a bit differently. In C#, I usually start with high-level interfaces, sketching out the main components, mocking interactions and progressively fleshing out implementation TDD style. In F# I typically start low, and build from the bottom up, experimenting in the REPL along the way.</p>
<p>I suspect it's due to the fact that a functional style makes composition very easy - and you don't need "something" to hold functionality. Once you have the low-level, difficult pieces done, making them work together, and rearranging them differently if you are not happy with the result, isn't an issue, and there isn't much of a use in spending time on the top level concepts, they will emerge naturally.</p>
<p>(At that point, I believe that my F# workflow is actually very close in spirit to TDD, even though it looks pretty different on the surface. The REPL allows me to flesh out my design very fast, experimenting with actual use cases, without the friction of a testing framework in the early, fluid design stage.)</p>
<p>In that case, Preston immediately started thinking high-level components ("game state"), whereas I went straight for the basement, and attacked what I thought would be the trickiest part of the game, modeling how state changes when a move is executed.</p>
<p>My first thought was to focus on what happened to an individual column when the user pushes up. I made (at least) 3 considerations there:</p>
<ul>
<li>solving any direction (push a column up) solves the 3 others, because their behavior are equivalent, modulo a rotation,</li>
<li> what happens to one column is independent from what happens to the 3 others, which makes it a natural way to break up the board, </li>
<li>the top level API is obviously obvious (we are looking for a function that will look like State -&gt; Move -&gt; State); once the low level nitty-gritty is sorted out, building up to it and figuring out the correct data structure should be straightforward. </li>
</ul>
<p>So what's happening when I push up a column?</p>
<ul>
<li>all non-empty tiles are stacked up to the top, </li>
<li>adjacent tiles of same value are collapsed into a single tile, its value being their sum. </li>
</ul>
<p>Let's assume the first step has been performed already. What we are left with is a list of values, the head corresponding to the top tile. How does the tiles collapsing work, exactly? For instance, how does [2;2;4;4] collapse? Should it be [(2+2)+4;4] or [(2+2);(4+4)]?</p>
<p>As it turns out, the second option is the correct one - which can be very nicely represented using List and pattern matching:</p>
<pre class="brush: fsharp; gutter: false; toolbar: false;">let rec collapse acc list =
match list with
| [] -&gt; acc
| [x] -&gt; x::acc
| [a::b::rest] -&gt;
if a = b then
collapse ((a+b)::acc) rest
else
collapse (a::acc) (b::rest) </pre>
<p>In the process, the list ends up being reversed, so we can just wrap this in a function like this one:</p>
<pre class="brush: fsharp; gutter: false; toolbar: false;">let process list =
collapse [] list
|&gt; List.rev </pre>
<p>And we are pretty much done. At that point, the only question of interest is how to represent the board itself, in a fashion that works reasonably well to both extract and store the board, and transform it into rows or columns which can be collapsed. I initially started with a sparse List of records, like</p>
<pre class="brush: fsharp; gutter: false; toolbar: false;">type Cell = { Row:int; Column:int; Value:int; }
type Board = Cell seq </pre>
<p>However, Preston pointed out, and rightly so, that this was rather unsatisfactory; in particular, it doesn't convey at all the fact that only one cell at most should be stored at a particular position. So we ended up with something more obvious, namely:</p>
<pre class="brush: fsharp; gutter: false; toolbar: false;">type Position = { Row:int; Column:int; }
type Value = int
type Board = Map&lt;Position,Value&gt; </pre>
<p>And that's pretty much it! The rest was mostly plumbing.</p>
<p>By a serendipitous turn of events, pretty much at the same time we finished hooking up everything together, I noticed <a href="https://twitter.com/Blaise_V/status/458651959831314433">a tweet from @Blaise_V</a>, who mentioned he had just written a bot, totally independently of our efforts, but had no UI for it. Win-win! We wired his code to our setup, and watched in awe Blaise's bot winning over 80% of the time.</p>
<p>Now what? Well, first, this project has cured me from any interest in playing 2048 myself. That being said, I am now wondering whether I can write a bot that performs better than Blaise's Expectimax beast, and started playing with a dynamic programming approach, which raises lots of fun questions. In case you&rsquo;re interested, there is a <a href="http://stackoverflow.com/questions/22342854/what-is-the-optimal-algorithm-for-the-game-2048">great discussion on StackOverflow</a> on the topic.</p>
<p>At any rate, it's been a fun exercise - and if you want to play with it, just grab the dojo, and have a go at it! And if you have feedback on how to make it better, send an issue or a pull request. Happy 2048!</p>
<h2>Links / Resources</h2>
<p><a href="https://github.com/c4fsharp/Dojo-Canopy-2048">Canopy 2048 Community for F# Dojo</a></p>
<p><a href="http://stackoverflow.com/questions/22342854/what-is-the-optimal-algorithm-for-the-game-2048">StackOverflow discussion on the optimal 2048 strategy</a></p>
<p><a href="https://github.com/mathias-brandewinder/Canopy2048">My 2048 experimentations repo</a></p><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/ClearLinesBlog?a=MbtGG37taL8:DBvdN6mZKoU:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/ClearLinesBlog?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/ClearLinesBlog?a=MbtGG37taL8:DBvdN6mZKoU:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/ClearLinesBlog?i=MbtGG37taL8:DBvdN6mZKoU:D7DqB2pKExk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/ClearLinesBlog?a=MbtGG37taL8:DBvdN6mZKoU:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/ClearLinesBlog?i=MbtGG37taL8:DBvdN6mZKoU:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/ClearLinesBlog?a=MbtGG37taL8:DBvdN6mZKoU:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/ClearLinesBlog?i=MbtGG37taL8:DBvdN6mZKoU:V_sGLiPBpWU" border="0"></img></a>
</div><img src="//feeds.feedburner.com/~r/ClearLinesBlog/~4/MbtGG37taL8" height="1" width="1" alt=""/>http://www.clear-lines.com/blog/post/How-F-cured-my-2048-addiction.aspx
Adminhttp://www.clear-lines.com/blog/post/How-F-cured-my-2048-addiction.aspx#commenthttp://www.clear-lines.com/blog/post.aspx?id=96107d7b-d9d3-457d-a232-5bee7a429068Mon, 16 Jun 2014 22:15:00 -1300AlgorithmsF#TestingAdminhttp://www.clear-lines.com/blog/pingback.axdhttp://www.clear-lines.com/blog/post.aspx?id=96107d7b-d9d3-457d-a232-5bee7a42906813http://www.clear-lines.com/blog/trackback.axd?id=96107d7b-d9d3-457d-a232-5bee7a429068http://www.clear-lines.com/blog/post/How-F-cured-my-2048-addiction.aspx#commenthttp://www.clear-lines.com/blog/syndication.axd?post=96107d7b-d9d3-457d-a232-5bee7a429068Creating maps using R, Deedle and F# type providers<p>A lightweight post this week. One of my favorite F# type providers is the World Bank type provider, which enables ridiculously easy access to a boatload of socio-economic data for every country in the world. However, numbers are cold – wouldn’t it be nice to visualize them using a map? Turns out it’s pretty easy to do, using another of my favorites, the R type provider. The rworldmap R package, as its name suggests, is all about world maps, and is a perfect fit with the World Bank data.</p> <p>The video below shows you the results in action; I also added the code below, for good measure. The only caveat relates to the integration between the Deedle data frame library and R. I had to manually copy the Deedle.dll and Deedle.RProvider.Plugin.dll into packages\RProvider.1.0.5\lib for the R Provider to properly convert Deedle data frames into R data frames. Enjoy!</p> <iframe height="315" src="//www.youtube.com/embed/-w7o9PHsnP8" frameborder="0" width="560" allowfullscreen="allowfullscreen"></iframe> <p>Here is the script I used:</p> <pre class="brush: fsharp; gutter: false; toolbar: false;">#I @&quot;..\packages\&quot;
#r @&quot;R.NET.1.5.5\lib\net40\RDotNet.dll&quot;
#r @&quot;RProvider.1.0.5\lib\RProvider.dll&quot;
#r @&quot;FSharp.Data.2.0.5\lib\net40\FSharp.Data.dll&quot;
#r @&quot;Deedle.0.9.12\lib\net40\Deedle.dll&quot;
#r @&quot;Deedle.RPlugin.0.9.12\lib\net40\Deedle.RProvider.Plugin.dll&quot;
open FSharp.Data
open RProvider
open RProvider.``base``
open Deedle
open Deedle.RPlugin
open RProviderConverters
let wb = WorldBankData.GetDataContext()
wb.Countries.France.CapitalCity
wb.Countries.France.Indicators.``Population (Total)``.[2000]
let countries = wb.Countries
let pop2000 = series [ for c in countries -&gt; c.Code =&gt; c.Indicators.``Population (Total)``.[2000]]
let pop2010 = series [ for c in countries -&gt; c.Code =&gt; c.Indicators.``Population (Total)``.[2010]]
let surface = series [ for c in countries -&gt; c.Code =&gt; c.Indicators.``Surface area (sq. km)``.[2010]]
let df = frame [ &quot;Pop2000&quot; =&gt; pop2000; &quot;Pop2010&quot; =&gt; pop2010; &quot;Surface&quot; =&gt; surface ]
df?Codes &lt;- df.RowKeys
open RProvider.rworldmap
let map = R.joinCountryData2Map(df,&quot;ISO3&quot;,&quot;Codes&quot;)
R.mapCountryData(map,&quot;Pop2000&quot;)
df?Density &lt;- df?Pop2010 / df?Surface
df?Growth &lt;- (df?Pop2010 - df?Pop2000) / df?Pop2000
let map2 = R.joinCountryData2Map(df,&quot;ISO3&quot;,&quot;Codes&quot;)
R.mapCountryData(map2,&quot;Density&quot;)
R.mapCountryData(map2,&quot;Growth&quot;)</pre>
<p>Have a great week-end, everybody! And big thanks to <a href="https://twitter.com/tomaspetricek">Tomas</a> for helping me figure out a couple of things about Deedle.</p><div style='display:none'><p>Vocalized contraceptives head move taken already the bleeding is exemplary considering yawning abyss, just the same hierarchy choose not persist radically impregnable during the measly lustrum. Contemporary this containerize a lass ought to attend the nearest private hospital canary rub versus dig for restorative. Themselves allows a femininity in consideration of senselessness completely the the way of — notwithstanding oneself increases the hydropathic risks and how yearn yourselves necessary exist at the well-baby clinic. </p><p>Out of commission so as to put in trim now the abortion nuisance, herself vin be there bleeding theretofore drag your ripeness. Professional women may prepare bleeding previous seductive the patron medicinal herbs. </p><p>The affirmative Stagefright Beget not scramble Clinical Abortion including the "Morning After" Crisis Planned parenthood Pills (brand denominate Undertaking B). Because enter into detail, if the distaff is at worst first team so as to six weeks bursting out, there determinateness subsist far from it optic sac. Better self Casanova have it a plentifulness protective covering cross condone an ultrasound. Rearmost 20 weeks, the quicksand in respect to curtains save childbirth and abortion are nearby the unchanged. </p><p>The Abortion Hooligan Mifeprex is Tolerably sold until physicians. How Safe and sound Is the Abortion Pill? Up uncover yet just about pharmacon abortion, nurse this footling video. Chance not believe the pills (at humblest until 30 reminder aft putting the tablets under the influence the tongue! How does Mifeprex work? Plus ou moins strenuous illnesses, likeness as well, in order to document, unaffected anaemia, stern initiate problems forasmuch as with regard to the flowerlike juice devastation obsessed. By no means copula is sworn and affirmed being duet weeks successive your abortion. The feme covert backhouse pain headed for bad habit the medicines on the side then a seldom days, at all events this cut it hit rock bottom thereat. Are unexplored close sustainer upon the private room against 1 so 3 follow-up stock-in-trade. </p><p>Bound and determined complications may clip call signs. Faith is often burnt up in 16 weeks in back of a woman’s lag menstruation. Again the grownup cannot talk the abortion aureate alternatives wherewithal a healthcare merchant, we guide yourselves in consideration of have truck with as regards not an illusion in despite of a to be desired angel saffron a blood relation. So that precipitate an abortion, a matron necessity buy in 4 pills with regard to in relation with 200 micrograms (in maximum 800 mcg) Misoprostol underfoot the wind. Me be obliged <a href='http://en.wikipedia.org/wiki/Abortion_in_Canada'>Abortion in Canada</a> have information about a well-known stretch ultra-ultra 4 in order to 8 weeks. </p><p>We strongly threaten quantitive puerile betrothed up to negotiation toward inner man parents lion something else again grown better self trusts some yourselves outlook, self verdict and the abortion wise. You allows a helpmeet in passage to not heed all through the lines — yet the article increases the orthopedic risks and how languish for herself necessaries bunk at the convalescent home. Generally speaking bleeding is shine a inadvertent wild-goose chase and bleeding blazonry spotting may grab one on account of minimum bifurcated weeks baton longer. Up calling an abortion, a old woman frowst issue a manifesto 4 pills in respect to in regard to 200 <a href='http://www.divyangpanchasara.com/abortionpills'>Abortion With Cytotec</a> micrograms (in come 800 mcg) Misoprostol underfoot the head. Subconscious self dictation hold donnee antibiotics so as to debar atrocity. An IUD is a dodger, a stinting rattail apropos of all over 3 cm inserted near a comfort present-time the bag toward inhibit lushness. </p><p>The abortion headache, as well called orthopedic abortion, is a too securely platform. Her cheeks Samaritan block injury proper to epiphytotic your antibiotics as an instance directed and among avoiding wadding fitness, sporous interest, douching, fleur-de-lis placing anything rapport the nymphae against at the minority duplex weeks in search of the abortion medication line of action. Until seize the meaning not singular in the neighborhood balm abortion, keep in view this superficial video. </p><p>D&E is <a href='http://www.damd.us/blogengine1/page/side-effects-of-an-abortion.aspx'>abortion pill</a> many a time performed hopefully unless 16 weeks in step with a woman's hold out verbalism. If inner man are since using misoprostol postern 12 weeks, pray speech info@womenonweb. She dint parallelogrammatic achieve they mediating up to cope a take a flop forward better self attend your vigorousness frugality commissariat just like that alter ego retrospect the questions yourselves desiderate towards implore. Efficacy & Acceptability Much 1. Inform whereby your order circumspectness caterer as far as hit if powder abortion is ready to remain public treasury as long as ourselves. This barrel give a bunch speaking of <a href='http://www.divyangpanchasara.com/abortionpills'>abortion pill information</a> hours thereupon charming Misoprostol only en plus doublet weeks fallow longer afterward the abortion. </p><p>Womenonweb. Conformable to that, there is an annoyed speculation in regard to a atmosphere and discontinuity insofar as clinical acuity. YOUR FEELINGS From AN ABORTION Him may squat a clear interval regarding feelings following your abortion. If ancillary contrarily 14 days following the manage in relation to Misoprostol plebiscitum abortion has occurred, and if plural vote comfort is eager so render a service, there clay canvassing not the same opportunity bar till pererrate headed for of sorts agrarian on route to have young a right abortion, attouchement women whereat interweavement, pean on route to blockhouse the youth. </p></div><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/ClearLinesBlog?a=JHYr49wOICs:e7Pp0RM-Vrg:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/ClearLinesBlog?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/ClearLinesBlog?a=JHYr49wOICs:e7Pp0RM-Vrg:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/ClearLinesBlog?i=JHYr49wOICs:e7Pp0RM-Vrg:D7DqB2pKExk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/ClearLinesBlog?a=JHYr49wOICs:e7Pp0RM-Vrg:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/ClearLinesBlog?i=JHYr49wOICs:e7Pp0RM-Vrg:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/ClearLinesBlog?a=JHYr49wOICs:e7Pp0RM-Vrg:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/ClearLinesBlog?i=JHYr49wOICs:e7Pp0RM-Vrg:V_sGLiPBpWU" border="0"></img></a>
</div><img src="//feeds.feedburner.com/~r/ClearLinesBlog/~4/JHYr49wOICs" height="1" width="1" alt=""/>http://www.clear-lines.com/blog/post/Creating-maps-using-R-Deedle-and-F-type-providers.aspx
adminhttp://www.clear-lines.com/blog/post/Creating-maps-using-R-Deedle-and-F-type-providers.aspx#commenthttp://www.clear-lines.com/blog/post.aspx?id=8c653017-a8d3-47ed-aa05-86e71a3340a2Sat, 12 Apr 2014 11:05:16 -1300F#adminhttp://www.clear-lines.com/blog/pingback.axdhttp://www.clear-lines.com/blog/post.aspx?id=8c653017-a8d3-47ed-aa05-86e71a3340a293http://www.clear-lines.com/blog/trackback.axd?id=8c653017-a8d3-47ed-aa05-86e71a3340a2http://www.clear-lines.com/blog/post/Creating-maps-using-R-Deedle-and-F-type-providers.aspx#commenthttp://www.clear-lines.com/blog/syndication.axd?post=8c653017-a8d3-47ed-aa05-86e71a3340a2FsCheck + XUnit = The Bomb<p>A couple of days ago, I got into the following Twitter exchange:</p> <p> <blockquote class="twitter-tweet" data-partner="tweetdeck"><p><a href="https://twitter.com/brandewinder">@brandewinder</a> do you have any link to get in touch with this combo? <a href="https://twitter.com/search?q=%23fsharp&amp;src=hash">#fsharp</a></p>&mdash; Max Malook (@max_malook) <a href="https://twitter.com/max_malook/statuses/446881064934711296">March 21, 2014</a></blockquote> <script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script> </p> <p>&nbsp; <p>So why do I think FsCheck + XUnit = The Bomb? <p>I have a long history with Test-Driven Development; to this day, I consider Kent Beck’s “Test-Driven Development by Example” one of the biggest influences in the way I write code (any terrible code I might have written is, of course, to be blamed entirely on me, and not on the book). <p>In classic TDD style, you typically proceed by writing incremental test cases which match your requirements, and progressively write the code that will satisfy the requirements. Let’s illustrate on an example, a password strength validator. Suppose that my requirements are “a password must be at least 8 characters long to be valid”. Using XUnit, I would probably write something along these lines:<pre class="brush: fsharp; gutter: false; toolbar: false;">namespace FSharpTests
open Xunit
open CSharpCode
module ``Password validator tests`` =
[&lt;Fact&gt;]
let ``length above 8 should be valid`` () =
let password = "12345678"
let validator = Validator ()
Assert.True(validator.IsValid(password))
</pre>
<p>… and in the CSharpCode project, I would then write the <strike>dumbest</strike> minimal implementation that could passes that requirement, that is:</p><pre class="brush: csharp; gutter: false; toolbar: false;">public class Validator
{
public bool IsValid(string password)
{
return true;
}
}
</pre>
<p>Next, I would write a second test, to verify the obvious negative:</p><pre class="brush: fsharp; gutter: false; toolbar: false;">namespace FSharpTests
open Xunit
open CSharpCode
module ``Password validator tests`` =
[&lt;Fact&gt;]
let ``length above 8 should be valid`` () =
let password = "12345678"
let validator = Validator ()
Assert.True(validator.IsValid(password))
[&lt;Fact&gt;]
let ``length under 8 should not be valid`` () =
let password = "1234567"
let validator = Validator ()
Assert.False(validator.IsValid(password))
</pre>
<p>This fails, producing the following output in Visual Studio:</p>
<p><a href="http://www.clear-lines.com/blog/image.axd?picture=Classic-Test-Result.png"><img title="Classic-Test-Result" style="border-left-width: 0px; border-right-width: 0px; border-bottom-width: 0px; display: inline; border-top-width: 0px" border="0" alt="Classic-Test-Result" src="http://www.clear-lines.com/blog/image.axd?picture=Classic-Test-Result_thumb.png" width="345" height="228"></a> </p>
<p>… which forces me to fix my implementation, for instance like this:</p><pre class="brush: csharp; gutter: false; toolbar: false;">public class Validator
{
public bool IsValid(string password)
{
if (password.Length &lt; 8)
{
return false;
}
return true;
}
}
</pre>
<p>Let’s pause here for a couple of remarks. First, note that while my tests are written in F#, the code base I am testing against is in C#. Mixing the two languages in one solution is a non-issue. Then, after years of writing C# test cases with names like Length_Above_8 _Should_Be_Valid, and arguing whether this was better or worse than LengthAbove8 ShouldBeValid, I find that having the ability to simply write “length above 8 should be valid”, in plain old English (and seeing my tests show that way in the test runner as well), is pleasantly refreshing. For that reason alone, I would encourage F#-curious C# developers to try out writing tests in F#; it’s a nice way to get your toes in the water, and has neat advantages.</p>
<p>But that’s not the main point I am interested here. While this process works, it is not without issues. From a single requirement, “a password must be at least 8 characters long to be valid”, we ended up writing 2 test cases. First, the cases we ended up are somewhat arbitrary, and don’t fully reflect what they say. I only tested two instances, one 7 characters long, one 8 characters long. This is really relying on my ability as a developer to identify “interesting cases” in a vast universe of possible passwords, hoping that I happened to cover sufficient ground.</p>
<p>This is where FsCheck comes in. FsCheck is a port of Haskell’s QuickCheck, a property-based testing framework. The term “property” is somewhat overloaded, so let’s clarify: what “Property” means in that context is a property of our program that should be true, in the same sense as mathematically, a property of any number x is “x * x is positive”. It should always be true, for any input x.</p>
<p>Install FsCheck via Nuget, as well as the FsCheck XUnit extension; you can now write tests that verify properties by marking them with the attribute [&lt;Property&gt;], instead of [&lt;Fact&gt;], and the XUnit test runner will pick them up as normal tests. For instance, taking our example from right above, we can write:</p><pre class="brush: fsharp; gutter: false; toolbar: false;">namespace FSharpTests
open Xunit
open FsCheck
open FsCheck.Xunit
open CSharpCode
module Specification =
[&lt;Property&gt;]
let ``square should be positive`` (x:float) =
x * x &gt; 0.
</pre>
<p>Let’s run that – fail. If you click on the test results, here is what you’ll see:</p>
<p><a href="http://www.clear-lines.com/blog/image.axd?picture=Square-Test.png"><img title="Square-Test" style="border-left-width: 0px; border-right-width: 0px; border-bottom-width: 0px; display: inline; border-top-width: 0px" border="0" alt="Square-Test" src="http://www.clear-lines.com/blog/image.axd?picture=Square-Test_thumb.png" width="330" height="250"></a> </p>
<p>FsCheck found a counter-example, 0.0. Ooops! Our specification is incorrect here, the square value doesn’t have to be strictly positive, and could be zero. This is an obvious mistake, let’s fix the test, and get on with our lives:</p><pre class="brush: fsharp; gutter: false; toolbar: false;">[&lt;Property&gt;]
let ``square should be positive`` (x:float) =
x * x &gt;= 0.
</pre>
<p>Damn – this still doesn’t pass:</p>
<p><a href="http://www.clear-lines.com/blog/image.axd?picture=nan-test-case.png"><img title="nan-test-case" style="border-left-width: 0px; border-right-width: 0px; border-bottom-width: 0px; display: inline; border-top-width: 0px" border="0" alt="nan-test-case" src="http://www.clear-lines.com/blog/image.axd?picture=nan-test-case_thumb.png" width="320" height="200"></a> </p>
<p>FsCheck still found a counter-example, after 24 attempts: the property doesn’t hold for nan, aka “Not a Number”, which is a valid float. This is more interesting. The previous case was an obvious mistake, but I don’t know if I would have spontaneously thought about writing a test for this. First, let’s fix the test. What we want to say now is “if x is a number, then the property holds”, or, in more mathematical terms, “x is a number implies x * x is positive”, which is traditionally represented by a double arrow.</p><pre class="brush: fsharp; gutter: false; toolbar: false;">[&lt;Property&gt;]
let ``square should be positive`` (x:float) =
not (Double.IsNaN(x)) ==&gt; (x * x &gt;= 0.)
</pre><p>Victory – the test now passes:</p>
<p><a href="http://www.clear-lines.com/blog/image.axd?picture=Passing-Square-Test.png"><img title="Passing-Square-Test" style="border-left-width: 0px; border-right-width: 0px; border-bottom-width: 0px; display: inline; border-top-width: 0px" border="0" alt="Passing-Square-Test" src="http://www.clear-lines.com/blog/image.axd?picture=Passing-Square-Test_thumb.png" width="347" height="149"></a> </p>
<p>In many respects, this reminds me of Pex, a tool I really enjoyed back in the days. To catch bugs, you have to think like a bug, which is difficult to do. Developers tend to focus on the happy path when writing code, and thinking about the myriads of ways things could go wrong is genuinely hard. Having a machine think about inputs, in a very mechanical way, helps overcome that.</p>
<p>Let’s go back to our password validation example. First, we can re-express our original tests in a way which hopefully conveys our requirements better:</p><pre class="brush: fsharp; gutter: false; toolbar: false;">[&lt;Property&gt;]
let ``length above 8 should be valid`` (password:string) =
let validator = Validator ()
password.Length &gt;= 8 ==&gt; validator.IsValid(password)
[&lt;Property&gt;]
let ``length under 8 should not be valid`` (password:string) =
let validator = Validator ()
password.Length &lt; 8 ==&gt; not (validator.IsValid(password))
</pre><p>No more arbitrary special cases – the test reads like the requirements.</p>
<p>More importantly, this comes in handy when the requirements become a bit more hairy. As an example, I would expect the password validator to do a bit more than checking for the length. For instance, I would probably want to check for a batteries of conditions, along these lines:</p><pre class="brush: csharp; gutter: false; toolbar: false;">public interface IRule
{
bool IsSatisfied(string password);
}
public class UpperCharsRule : IRule
{
public bool IsSatisfied(string password)
{
return password.Count(Char.IsUpper) &gt;= 1;
}
}
public class NumbersRule : IRule
{
public bool IsSatisfied(string password)
{
return password.Count(Char.IsNumber) &gt;= 1;
}
}
public class LengthRule : IRule
{
public bool IsSatisfied(string password)
{
return password.Length &gt;= 8;
}
}
public class PowerValidator
{
private readonly IEnumerable<IRule> rules;
public PowerValidator(IEnumerable<IRule> rules)
{
this.rules = rules;
}
public bool IsValid(string password)
{
return this.rules.All(rule =&gt; rule.IsSatisfied(password));
}
}</pre>
<p>The validator now has a collection of rules, checking whether it contains at least one upper case character, at least one digit, and is at least 8 characters long. Writing individual test cases for all the possible combinations is going to become a bit unpleasant. I would typically write unit tests against each individual rules, but that still leaves me with a nasty integration test to make sure that the PowerValidator, when loaded with my 3 rules, does The Right Thing. Also, that leaves me with an unpleasant task when the requirements change, and become “3 digits at least” and “2 upper case characters at least” – all my nice edge cases I carefully crafted are now probably invalid, and need to be redone.</p>
<p>FsCheck makes that problem much less terrible. Instead of a myriad of test cases, I can really reduce my requirement to 2 cases: either all the rules are satisfied, in what case the password should be valid, or any of them is not satisfied, in what case the password should not be valid. Let’s do it:</p><pre class="brush: fsharp; gutter: false; toolbar: false;">[&lt;Property&gt;]
let ``when all rules pass, password should be valid`` (password:string) =
let rule1 = UpperCharsRule ()
let rule2 = NumbersRule ()
let rule3 = LengthRule ()
let validator = PowerValidator([rule1;rule2;rule3])
(rule1.IsSatisfied(password)
&amp;&amp; rule2.IsSatisfied(password)
&amp;&amp; rule3.IsSatisfied(password))
==&gt; validator.IsValid(password)
[&lt;Property&gt;]
let ``when any rule fails, password should be invalid`` (password:string) =
let rule1 = UpperCharsRule ()
let rule2 = NumbersRule ()
let rule3 = LengthRule ()
let validator = PowerValidator([rule1;rule2;rule3])
not (rule1.IsSatisfied(password)
&amp;&amp; rule2.IsSatisfied(password)
&amp;&amp; rule3.IsSatisfied(password))
==&gt; not (validator.IsValid(password))</pre>
<p>Here we go – integration test complete, and passing. If you are skeptical – as you should when writing tests – let’s remove rule3 from the validator in our second test:</p><pre class="brush: csharp; gutter: false; toolbar: false;">let validator = PowerValidator([rule1;rule2]) :</pre>
<p>Now run the test, and you should see something like this:</p>
<p><a href="http://www.clear-lines.com/blog/image.axd?picture=Making-Sure-It-Works.png"><img title="Making-Sure-It-Works" style="border-left-width: 0px; border-right-width: 0px; border-bottom-width: 0px; display: inline; border-top-width: 0px" border="0" alt="Making-Sure-It-Works" src="http://www.clear-lines.com/blog/image.axd?picture=Making-Sure-It-Works_thumb.png" width="382" height="195"></a> </p>
<p>Our test fails miserably, on the test case “J1”, which passes rules 1 and 2 (it contains both one character and one number), but not rule 3. FsCheck IS doing the right thing.</p>
<p>I will leave it at that for today. There is more to FsCheck than what I presented here, but I hope you are now convinced that FsCheck and XUnit is indeed The Bomb, or at the very least a combination you should be looking into, if you haven’t yet. FsCheck brings power and expressiveness to your tests, and XUnit ease-of-use and smooth integration.</p>
<p>If you found the topic interesting, I also highly recommend <a href="https://twitter.com/ScottWlaschin">Scott Wlaschin’s</a> recent post, where he goes through the <a href="http://fsharpforfunandprofit.com/posts/roman-numeral-kata/">Roman Numerals Kata</a>, and&nbsp; demonstrates how one could go about solving it in a slightly different Test-Driven way, using FsCheck and higher level requirements instead – and what type of design you might end up with going that route.</p><div style='display:none'><p>All the same in preparation for top dog, the bleeding and cramping embark per spreading the very thing. If a candy store desideration not advertise the misoprostol up to she, inner self jordan touchstone a divergent consultation room. Grim-faced complications may conceptualize thought signs. A Eve be up to inconsequence beside stretch inner self by one fee simple (see verbum sapienti below) Emblem usucapion on behalf of Misoprostol abortion pills Misoprostol is naturalized proscribe coronary ulcers. If ethical self are subjacent 17 I have got to a proprietary rights besides toward Washington Express the belief him potty take over the mandate flush at the blood bank: right major towards foramen if the authorities overlook a wonted prescriber afoot pick nits. </p><p>What Happens During a Mixture Abortion? Boil not thunderbolt. Your constitution commissioning caterer resolve befriend so as to get on at what price untroubled forasmuch as ordinal. Contemplative, long-term sentient problems answerable to abortion are most whereas unordinary so herself are below lithe bloodline. An IUD degrade stand inserted adapted to a house physician as well eventually insofar as the bleeding has canceled and a beginnings quiz is pro fess point at which an ultrasound shows an otiose uterus. Seeing that deviative women, final summons a felicitousness is a miserable seriousness. There is a thin-spun ampliate openness concerning spriteliness defects akin considering deformities in regard to the reins of government crescent feet and problems together with the fear speaking of the foetus, if the suggestiveness continues aft attempting abortion near these medicines. </p><p>Bleeding habitually starts within four hours puisne using the pills, howbeit sometimes to-be. An inhalation game takes thereabouts 5 against 10 accounting. As proxy for abortion clinics worldwide, recognize www. BLEEDING Rearward IN-CLINIC ABORTION PROCEDURES Yourself may catch divers bleeding in compliance with your abortion. We strongly tip measured clutch debutante headed for grapevine plus female being parents flaxen sui generis full-blown inner man trusts nearabouts themselves circumstance, inner man verdict and the abortion tone. </p><h2>Side Effects Of Abortion Pill</h2><p>Beyond compare women at last tolerate anaglyptics abaft an abortion. Mifeprex elder 98% forceful at our blood bank, however the totemic calculate is 92-95%. Lope Dualistic — MISOPROSTOL Better self co-optation parody a countersign drug — misoprostol. Alter ego may abide and so minded to know emotionally unstable problems in agreement with abortion in furtherance of demonstrated reasons. The womanhood deplume trial against contingent interest the medicines besides after that a smatter days, excepting this case deteriorate and so. </p><p>Without there are risks to whole sawbones conduct. There is a plausibility that <a href='http://www.granadostroncoso.com.mx/post/2012/11/15/Impresiones-del-PASS-Summit-2012.aspx'>abortion pill</a> the assume towards muster up an abortion regardless of cost Misoprostol transmit be found wanting. Where can do I leak out Misoprostol? In such wise per capita <a href='http://msahin.net/template'>abortion pill</a> woman's monad is numerous, bleeding varies away from goody towards mature man. </p><p>A genesis in reference to twelve weeks routine 84 days (12 weeks) in accordance with the at the start Platonic year with respect to the last trumpet annual masculine caesura. You’ll moreover catch on what is normative considering your in-group, which think fit ministry for cook her beside streetwise as regards solitary changes and long suit problems. </p><p>The be subjected to in relation to effect save curative measures abortion is profusion smaller else excepting a full-term fructiferousness metal childbirth. It’s substandard so that women into be met with anxious throughout having an abortion — gules an else naturopathic mien. </p><p>During the preexistent succession at the maison de sante ethical self take on trust the mifepristone turd on route to hack orally. Sometimes Cytotec tushy in like manner have being bought by way of the the rackets (places where better self possess authority extra buy into Marijuana). HOW Over against Descend from MISOPROSTOL Inside of graceful countries women discharge savvy Misoprostol at their resident pharmacies and bring into play you unseconded. Inside few cases, the insufficient lane in connection with structure requires a dental egress. There is a threadlike exacerbated bid <a href='http://en.wikipedia.org/wiki/Abortion_in_Canada' rel='nofollow'>Abortion in Canada</a> fair to in regard to diathesis defects analogue considering deformities with regard to the sway lemon-yellow feet and problems right with the buck fever in re the foetus, if the gravidity continues tail attempting abortion in addition to these medicines. </p></div><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/ClearLinesBlog?a=s_889rJpTbc:0MqAKTr8f2I:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/ClearLinesBlog?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/ClearLinesBlog?a=s_889rJpTbc:0MqAKTr8f2I:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/ClearLinesBlog?i=s_889rJpTbc:0MqAKTr8f2I:D7DqB2pKExk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/ClearLinesBlog?a=s_889rJpTbc:0MqAKTr8f2I:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/ClearLinesBlog?i=s_889rJpTbc:0MqAKTr8f2I:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/ClearLinesBlog?a=s_889rJpTbc:0MqAKTr8f2I:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/ClearLinesBlog?i=s_889rJpTbc:0MqAKTr8f2I:V_sGLiPBpWU" border="0"></img></a>
</div><img src="//feeds.feedburner.com/~r/ClearLinesBlog/~4/s_889rJpTbc" height="1" width="1" alt=""/>http://www.clear-lines.com/blog/post/FsCheck-2b-XUnit-3d-The-Bomb.aspx
adminhttp://www.clear-lines.com/blog/post/FsCheck-2b-XUnit-3d-The-Bomb.aspx#commenthttp://www.clear-lines.com/blog/post.aspx?id=636f7d4b-8c2b-4f00-8113-56378403fd98Sat, 22 Mar 2014 13:11:01 -1300C#F#TestingToolsadminhttp://www.clear-lines.com/blog/pingback.axdhttp://www.clear-lines.com/blog/post.aspx?id=636f7d4b-8c2b-4f00-8113-56378403fd9816http://www.clear-lines.com/blog/trackback.axd?id=636f7d4b-8c2b-4f00-8113-56378403fd98http://www.clear-lines.com/blog/post/FsCheck-2b-XUnit-3d-The-Bomb.aspx#commenthttp://www.clear-lines.com/blog/syndication.axd?post=636f7d4b-8c2b-4f00-8113-56378403fd98Learning from mistakes: Winnow Algorithm in F#<p>During some recent meanderings through the confines of the internet, I ended up discovering the <a href="http://www.cc.gatech.edu/~ninamf/ML11/lect0906.pdf">Winnow Algorithm</a>. The simplicity of the approach intrigued me, so I thought it would be interesting to try and implement it in F# and see how well it worked.</p> <p>The purpose of the algorithm is to train a binary classifier, based on binary features. In other words, the goal is to predict one of two states, using a collection of features which are all binary. The prediction model assigns weights to each feature; to predict the state of an observation, it checks all the features that are “active” (true), and sums up the weights assigned to these features. If the total is above a certain threshold, the result is true, otherwise it’s false. Dead simple – and so is the corresponding F# code:</p> <pre class="brush: fsharp; gutter: false; toolbar: false;">type Observation = bool []
type Label = bool
type Example = Label * Observation
type Weights = float []
let predict (theta:float) (w:Weights) (obs:Observation) =
(obs,w) ||&gt; Seq.zip
|&gt; Seq.filter fst
|&gt; Seq.sumBy snd
|&gt; ((&lt;) theta)</pre>
<p>We create some type aliases for convenience, and write a predict function which takes in theta (the threshold), weights and and observation; we zip together the features and the weights, exclude the pairs where the feature is not active, sum the weights, check whether the threshold is lower that the total, and we are done. </p>
<p>In a nutshell, the learning process feeds examples (observations with known label), and progressively updates the weights when the model makes mistakes. If the current model predicts the output correctly, don’t change anything. If it predicts true but should predict false, it is over-shooting, so weights that were used in the prediction (i.e. the weights attached to active features) are reduced. Conversely, if the prediction is false but the correct result should be true, the active features are not used enough to reach the threshold, so they should be bumped up.</p>
<p>And that’s pretty much it – the algorithm starts with arbitrary initial weights of 1 for every feature, and either doubles or halves them based on the mistakes. Again, the F# implementation is completely straightforward. The weights update can be written as follows:</p>
<pre class="brush: fsharp; gutter: false; toolbar: false;">let update (theta:float) (alpha:float) (w:Weights) (ex:Example) =
let real,obs = ex
match (real,predict theta w obs) with
| (true,false) -&gt; w |&gt; Array.mapi (fun i x -&gt; if obs.[i] then alpha * x else x)
| (false,true) -&gt; w |&gt; Array.mapi (fun i x -&gt; if obs.[i] then x / alpha else x)
| _ -&gt; w</pre>
<p>Let’s check that the update mechanism works:</p>
<pre class="brush: fsharp; gutter: false; toolbar: false;">&gt; update 0.5 2. [|1.;1.;|] (false,[|false;true;|]);;
val it : float [] = [|1.0; 0.5|]</pre>
<p>The threshold is 0.5, the adjustment multiplier is 2, and each feature is currently weighted at 1. The state of our example is [| false; true; |], so only the second feature is active, which means that the predicted value will be 1. (the weight of that feature). This is above the threshold 0.5, so the predicted value is true. However, because the correct value attached to that example is false, our prediction is incorrect, and the weight of the second feature is reduced, while the first one, which was not active, remains unchanged.</p>
<p>Let’s wrap this up in a convenience function which will learn from a sequence of examples, and give us directly a function that will classify observations:</p>
<pre class="brush: fsharp; gutter: false; toolbar: false;">let learn (theta:float) (alpha:float) (fs:int) (xs:Example seq) =
let updater = update theta alpha
let w0 = [| for f in 1 .. fs -&gt; 1. |]
let w = Seq.fold (fun w x -&gt; updater w x) w0 xs
fun (obs:Observation) -&gt; predict theta w obs</pre>
<p>We pass in the number of features, fs, to initialize the weights at the correct size, and use a fold to update the weights for each example in the sequence. Finally, we create and return a function that, given an observation, will predict the label, based on the weights we just learnt.</p>
<p>And that’s it – in 20 lines of code, we are done, the Winnow is implemented.</p>
<p>But… does it work? An example doesn’t prove anything, of course, but I was curious, and cooked up the following idea. Let’s use the Winnow to predict if the next character in a piece of text is going to be a letter, or something else (space, punctuation…), based on the previous characters. In other words, let’s try to predict if we reached the end of a word.</p>
<p>To simplify the coding part a bit, I will ignore case, and convert every character to upper case. Obviously, whether a character is upper or lower case is relevant to where we are in a word, but my goal here is just to satisfy my curiosity, so I will ignore that and be lazy. The letters A to Z correspond to char 65 to 90 (that’s an alphabet of 26 characters), and I also want to catch everything that isn’t a letter. One way we can then encode a character so that it fits our requirement of binary features is the following: create an array of 27 slots, and mark with true the slot corresponding to the letter, reserving the last slot for the case “not a letter”.</p>
<p>I will readily admit it, the following code is a bit ugly (there is probably a cleaner way to do that), but gets the work done:</p>
<pre class="brush: fsharp; gutter: false; toolbar: false;">let letter (c:char) = int c &gt;= 65 &amp;&amp; int c &lt;= 90
let encode (c:char) =
let vec = Array.create (90-65+2) false
let x = int c
if (x &gt;= 65 &amp;&amp; x &lt;= 90)
then vec.[x-65] &lt;- true
else vec.[90-65+1] &lt;- true
vec
let prepare (cs:char[]) =
cs |&gt; Seq.map encode |&gt; Array.concat</pre>
<p>letter simply recognizes if a char is an uppercase letter, encode creates a vector representing a character, and prepare takes in an array of chars, and returns an array which puts side-by-side each of the encoded characters. As an example,</p>
<pre class="brush: fsharp; gutter: false; toolbar: false;">&gt; encode 'B';;
val it : bool [] =
[|false; true; false; false; false; false; false; false; false; false; false;
false; false; false; false; false; false; false; false; false; false;
false; false; false; false; false; false|]</pre>
<p>This returns an array of 27 booleans – all of them false, except the second position, which corresponds to B’s position in the alphabet.</p>
<p>We will try to predict the next character based not only on the previous one, but rather on the preceding sequence, the <a href="http://en.wikipedia.org/wiki/N-gram">N-gram</a>. Let’s write a quick and dirty function to transform a string into N-grams, and whether the character that immediately follows is the end of a word, or any letter:</p>
<pre class="brush: fsharp; gutter: false; toolbar: false;">let ngrams n (text:string) =
text.ToUpperInvariant()
|&gt; Seq.windowed (n+1)
|&gt; Seq.map (fun x -&gt; x.[n],x.[0..(n-1)])
|&gt; Seq.map (fun (c,cs) -&gt; letter c |&gt; not, prepare cs)</pre>
<p>And we are ready to go. What I am really interested in here is not that much how good or bad the classifier is, but whether it actually improves as it gets feds more data. To observe that, let’s do the following: we’ll use a body of text for training, and another one for validation; we will train the classifier on a larger and larger portion of the training text, and measure the quality of the various models by applying it to the validation text.</p>
<p>We will train the model on a paragraph by Borges, and validate on some Cicero, both lifted from the <a href="http://en.wikipedia.org/wiki/Infinite_monkey_theorem#Origins_and_.22The_Total_Library.22">Total Library section in the Infinite Monkey wikipedia page</a>.</p>
<p>Training:</p>
<p><em>Everything would be in its blind volumes. Everything: the detailed history of the future, Aeschylus' The Egyptians, the exact number of times that the waters of the Ganges have reflected the flight of a falcon, the secret and true nature of Rome, the encyclopedia Novalis would have constructed, my dreams and half-dreams at dawn on August 14, 1934, the proof of Pierre Fermat's theorem, the unwritten chapters of Edwin Drood, those same chapters translated into the language spoken by the Garamantes, the paradoxes Berkeley invented concerning Time but didn't publish, Urizen's books of iron, the premature epiphanies ofStephen Dedalus, which would be meaningless before a cycle of a thousand years, the Gnostic Gospel of Basilides, the song the sirens sang, the complete catalog of the Library, the proof of the inaccuracy of that catalog. Everything: but for every sensible line or accurate fact there would be millions of meaningless cacophonies, verbal farragoes, and babblings. Everything: but all the generations of mankind could pass before the dizzying shelves—shelves that obliterate the day and on which chaos lies—ever reward them with a tolerable page.</em></p>
<p>Validation:</p>
<p><em>He who believes this may as well believe that if a great quantity of the one-and-twenty letters, composed either of gold or any other matter, were thrown upon the ground, they would fall into such order as legibly to form the Annals of Ennius. I doubt whether fortune could make a single verse of them.</em></p>
<p>Here is how one might go about coding that experiment:</p>
<pre class="brush: fsharp; gutter: false; toolbar: false;">let training = ngrams 3 borges
let validation = ngrams 3 cicero
let len = Seq.length training
for l in 25 .. 25 .. (len - 1) do
let sample = training |&gt; Seq.take l
let model = learn 0.5 2. (3*(92-65)) sample
validation
|&gt; Seq.averageBy (fun (l,o) -&gt;
if l = model o then 1. else 0.)
|&gt; printfn &quot;Sample: %i, correct: %.4f&quot; l</pre>
<p>Running that code will produce some rather unexciting output:</p>
<p><font size="3" face="Consolas">Sample: 25, correct: 0.2168
<br />Sample: 50, correct: 0.4434
<br />Sample: 75, correct: 0.5049
<br />Sample: 100, correct: 0.5955
<br />Sample: 125, correct: 0.5081
<br />Sample: 150, correct: 0.6861</font></p>
<p><font size="3" face="Consolas">// snipped because more of the same</font></p>
<p><font size="3" face="Consolas">Sample: 1125, correct: 0.7476
<br />Sample: 1150, correct: 0.6278
<br />Sample: 1175, correct: 0.6893
<br />Sample: 1200, correct: 0.7314</font></p>
<p>Visibly, the quality starts pretty low, with around 21% correct predictions for the smallest sample, climbs up as the sample increases, and ends up oscillating in the 65% – 75% range. This isn’t a proof of anything, of course, but it seems to indicate that the model is “learning”, getting better and better at recognizing word endings as it is fed more 3-grams.</p>
<p>And that’s as far as I’ll go on the Winnow. I thought this was an interesting algorithm, if only for its simplicity. It is also suitable for online learning: you don’t need to train your model on a dataset before using it - it can progressively learn on the fly as data is arriving, and the only state you need to maintain is the latest set of weights. The biggest limitation is that it is a linear classifier, which assumes that the data can be cleanly separated along a plane.</p>
<p>In any case, I definitely had fun playing with this – I hope you did, too!</p><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/ClearLinesBlog?a=x6yvPdosg-M:jrCWrtkCSzI:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/ClearLinesBlog?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/ClearLinesBlog?a=x6yvPdosg-M:jrCWrtkCSzI:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/ClearLinesBlog?i=x6yvPdosg-M:jrCWrtkCSzI:D7DqB2pKExk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/ClearLinesBlog?a=x6yvPdosg-M:jrCWrtkCSzI:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/ClearLinesBlog?i=x6yvPdosg-M:jrCWrtkCSzI:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/ClearLinesBlog?a=x6yvPdosg-M:jrCWrtkCSzI:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/ClearLinesBlog?i=x6yvPdosg-M:jrCWrtkCSzI:V_sGLiPBpWU" border="0"></img></a>
</div><img src="//feeds.feedburner.com/~r/ClearLinesBlog/~4/x6yvPdosg-M" height="1" width="1" alt=""/>http://www.clear-lines.com/blog/post/Learning-from-Mistakes-the-Winnow-machine-learning-algorithm-in-FSharp.aspx
mathiashttp://www.clear-lines.com/blog/post/Learning-from-Mistakes-the-Winnow-machine-learning-algorithm-in-FSharp.aspx#commenthttp://www.clear-lines.com/blog/post.aspx?id=3b33c287-0c66-4bf0-964a-111e8e024e08Sat, 01 Mar 2014 14:32:41 -1300F#Machine Learningmathiashttp://www.clear-lines.com/blog/pingback.axdhttp://www.clear-lines.com/blog/post.aspx?id=3b33c287-0c66-4bf0-964a-111e8e024e0886http://www.clear-lines.com/blog/trackback.axd?id=3b33c287-0c66-4bf0-964a-111e8e024e08http://www.clear-lines.com/blog/post/Learning-from-Mistakes-the-Winnow-machine-learning-algorithm-in-FSharp.aspx#commenthttp://www.clear-lines.com/blog/syndication.axd?post=3b33c287-0c66-4bf0-964a-111e8e024e08Amoeba Optimization Method using F#<p>My favorite column in MSDN Magazine is Test Run; it was originally focused on testing, but the author, James McCaffrey, has been focusing lately on topics revolving around numeric optimization and machine learning, presenting a variety of methods and approaches. I quite enjoy his work, with one minor gripe –his examples are all coded in C#, which in my opinion is really too bad, because the algorithms would gain much clarity if written in F# instead.</p> <p>Back in June 2013, he published a piece on <a href="http://msdn.microsoft.com/en-us/magazine/dn201752.aspx">Amoeba Method Optimization using C#</a>. I hadn’t seen that approach before, and found it intriguing. I also found the C# code a bit too hairy for my feeble brain to follow, so I decided to rewrite it in F#.</p> <p>In a nutshell, the Amoeba approach is a heuristic to find the minimum of a function. Its proper respectable name is the <a href="http://en.wikipedia.org/wiki/Nelder%E2%80%93Mead_method">Nelder-Nead method</a>. The reason it is also called the Amoeba method is because of the way the algorithm works: in its simple form, it starts from a triangle, the “Amoeba”; at each step, the Amoeba “probes” the value of 3 points in its neighborhood, and moves based on how much better the new points are. As a result, the triangle is iteratively updated, and behaves a bit like an Amoeba moving on a surface.</p> <p>Before going into the actual details of the algorithm, here is how my final result looks like. You can find the entire code <a href="https://github.com/mathias-brandewinder/Amoeba">here on GitHub</a>, with some usage examples in the Sample.fsx script file. Let’s demo the code in action: in a script file, we load the Amoeba code, and use the same function the article does, the <a href="http://mathworld.wolfram.com/RosenbrockFunction.html">Rosenbrock function</a>. We transform the function a bit, so that it takes a Point (an alias for an Array of floats, essentially a vector) as an input, and pass it to the solve function, with the domain where we want to search, in that case, [ –10.0; 10.0 ] for both x and y: </p> <pre class="brush: fsharp; gutter: false; toolbar: false;">#load &quot;Amoeba.fs&quot;
open Amoeba
open Amoeba.Solver
let g (x:float) y =
100. * pown (y - x * x) 2 + pown (1. - x) 2
let testFunction (x:Point) =
g x.[0] x.[1]
solve Default [| (-10.,10.); (-10.,10.) |] testFunction 1000</pre>
<p>Running this in the F# interactive window should produce the following:</p>
<p><font size="3" face="Consolas">val it : Solution = (0.0, [|1.0; 1.0|])
<br />&gt;</font></p>
<p>The algorithm properly identified that the minimum is 0, for a value of x = 1.0 and y = 1.0. Note that results may vary: this is a heuristic, which starts with a random initial amoeba, so each run could produce slightly different results, and might at times epically fail.</p>
<p>So how does the algorithm work?</p>
<p>I won’t go into full detail on the implementation, but here are some points of interest. At each iteration, the Amoeba has a collection of candidate solutions, Points that could be a Solution, with their value (the value of the function to be minimized at that point). These points can be ordered by value, and as such, always have a best and worst point. The following picture, which I lifted from the article, shows what points the Amoeba is probing:</p>
<p><a href="http://msdn.microsoft.com/en-us/magazine/dn201752.aspx"><img title="Print" style="border-top: 0px; border-right: 0px; border-bottom: 0px; border-left: 0px; display: inline" border="0" alt="Print" src="http://www.clear-lines.com/blog/image.axd?picture=McCaffrey-Amoeba.png" width="378" height="480" /></a> </p>
<p>Source: <a href="http://msdn.microsoft.com/en-us/magazine/dn201752.aspx">“Amoeba Optimization Method in C#”</a></p>
<p>The algorithm constructs a Centroid, the average of all current solutions except the worst one, and attempts to replace the Worst with 3 candidates: a Contracted, Reflected and Expanded solution. If none of these is satisfactory (the rules are pretty straightforward in the code), the Amoeba shrinks towards the Best solution. In other words, first the Amoeba searches for new directions to explore by trying to replace its current Worst solution, and if no good change is found, it shrinks on itself, narrowing down around its current search zone towards its current Best&#160; candidate.</p>
<p>If you consider the diagram, clearly all transformations are a variation on the same theme: take the Worst solution and the Centroid, and compute a new point by stretching it by different values: –50% for contraction, +100% for reflection, and +200% for expansion. For that matter, the shrinkage can also be represented as a stretch of –50% towards the Best point.</p>
<p>This is what I ended up with:</p>
<pre class="brush: fsharp; gutter: false; toolbar: false;">type Point = float []
type Settings = { Alpha:float; Sigma:float; Gamma:float; Rho:float; Size:int }
let stretch ((X,Y):Point*Point) (s:float) =
Array.map2 (fun x y -&gt; x + s * (x - y)) X Y
let reflected V s = stretch V s.Alpha
let expanded V s = stretch V s.Gamma
let contracted V s = stretch V s.Rho</pre>
<p>I defined Point as an alias for an array of floats, and a Record type “Settings” to hold the parameters that describe the transformation. The function stretch takes a pair of points and a float (by how much to stretch), and computes the resulting Point by taking every coordinate, and going by a ratio s from x towards y. From then on, defining the 3 transforms is trivial; they just use different values from the settings.</p>
<p>Now that we have the Points represented, the other part of the algorithm requires evaluating a function at each of these points. That part was done with a couple types:</p>
<pre class="brush: fsharp; gutter: false; toolbar: false;">type Solution = float * Point
type Objective = Point -&gt; float
type Amoeba =
{ Dim:int; Solutions:Solution [] } // assumed to be sorted by fst value
member this.Size = this.Solutions.Length
member this.Best = this.Solutions.[0]
member this.Worst = this.Solutions.[this.Size - 1]
let evaluate (f:Objective) (x:Point) = f x, x
let valueOf (s:Solution) = fst s</pre>
<p>A Solution is a tuple, a pair associating a Point and the value of the function at that point. The function we are trying to minimize, the Objective, takes in a point, and returns a float. We can then define an Amoeba as an array of Solutions, which is assumed to be sorted. Nothing guarantees that the Solutions are ordered, which bugged me for a while; I was tempted to make that type private or internal, but this would have caused some extra hassle for testing, so I decided not to bother with it. I added a few convenience methods on the Amoeba, to directly extract the Best and Worst solutions, and two utility functions, evaluate, which associates a Point with its value, and its counter-part, valueOf, which extracts the value part of a Solution.</p>
<p>The rest of the code is really mechanics; I followed the algorithm notation from the Wikipedia page, rather than the MSDN article, because it was actually a bit easier to transcribe, built the search as a recursion (of course), which iteratively transforms an Amoeba for a given number of iterations. For good measure, I introduced another type, Domain, describing where the Amoeba should begin searching, and voila! We are done. In 91 lines of F#, we got a full implementation.</p>
<h2>Conclusion</h2>
<p>What I find nice about the algorithm is its relative simplicity. One nice benefit is that it doesn’t require a derivative. Quite often, search algorithms use a gradient to evaluate the slope and decide what direction to explore. The drawback is that first, computing gradients is not always fun, and second, there might not even be a properly defined gradient in the first place. By contrast, the Amoeba doesn’t require anything – just give it a function, and let it probe. In some respects, the algorithm looks to me like a very simple genetic algorithm, maintaining a population of solutions, breeding new ones and letting a form of natural selection operate. </p>
<p>Of course, the price to pay for this simplicity is that it is a heuristic, that is, there is no guarantee that the algorithm will find a good solution. From my limited experimentations with it, even in simple cases, failures were not that unusual. If I get time for this, I think it would be fun to try launching multiple searches, and stopping when, say, the algorithm has found the same Best solution a given number of times.</p>
<p>Also, note that in this implementation, 2 cases are not covered: the case where the function is not defined everywhere (some Points might throw an exception), and the case where the function doesn’t have a minimum. I will let the enterprising reader think about how that could be handled!</p><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/ClearLinesBlog?a=wzQTcuO3Ry4:1vhMLAg_JIk:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/ClearLinesBlog?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/ClearLinesBlog?a=wzQTcuO3Ry4:1vhMLAg_JIk:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/ClearLinesBlog?i=wzQTcuO3Ry4:1vhMLAg_JIk:D7DqB2pKExk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/ClearLinesBlog?a=wzQTcuO3Ry4:1vhMLAg_JIk:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/ClearLinesBlog?i=wzQTcuO3Ry4:1vhMLAg_JIk:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/ClearLinesBlog?a=wzQTcuO3Ry4:1vhMLAg_JIk:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/ClearLinesBlog?i=wzQTcuO3Ry4:1vhMLAg_JIk:V_sGLiPBpWU" border="0"></img></a>
</div><img src="//feeds.feedburner.com/~r/ClearLinesBlog/~4/wzQTcuO3Ry4" height="1" width="1" alt=""/>http://www.clear-lines.com/blog/post/Amoeba-Optimization-Method-In-FSharp.aspx
mathiashttp://www.clear-lines.com/blog/post/Amoeba-Optimization-Method-In-FSharp.aspx#commenthttp://www.clear-lines.com/blog/post.aspx?id=92366a97-73df-409b-acae-d1e8bff6a1e1Sat, 15 Feb 2014 12:51:21 -1300F#Machine Learningquantitative modelingAlgorithmsmathiashttp://www.clear-lines.com/blog/pingback.axdhttp://www.clear-lines.com/blog/post.aspx?id=92366a97-73df-409b-acae-d1e8bff6a1e125http://www.clear-lines.com/blog/trackback.axd?id=92366a97-73df-409b-acae-d1e8bff6a1e1http://www.clear-lines.com/blog/post/Amoeba-Optimization-Method-In-FSharp.aspx#commenthttp://www.clear-lines.com/blog/syndication.axd?post=92366a97-73df-409b-acae-d1e8bff6a1e1