<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Go on FastDataScience.eu</title>
    <link>https://fastdatascience.eu/tags/go/</link>
    <description>FastDataScience.eu (Go)</description>
    <generator>Hugo -- gohugo.io</generator>
    <copyright>en-us</copyright>
    <lastBuildDate>Tue, 15 Oct 2024 00:00:00 +0000</lastBuildDate>
    
    <atom:link href="https://fastdatascience.eu/tags/go/index.xml" rel="self" type="application/rss+xml" />
    
    
    <item>
      <title>Comparing speed of some fast languages</title>
      <link>https://fastdatascience.eu/post/2024-10-18-zig_speed/</link>
      <pubDate>Tue, 15 Oct 2024 00:00:00 +0000</pubDate>
      <guid>https://fastdatascience.eu/post/2024-10-18-zig_speed/</guid>
      <description>&lt;p&gt;To get more familiar with Rust, I&amp;rsquo;ve lately been revisting last year&amp;rsquo;s
Advent of Code problems, which I did in Go last December. My
&lt;a href=&#34;https://github.com/andreaskaempf/adventofcode/blob/main/2023/day05/main.go&#34;&gt;Go solution&lt;/a&gt;
solution for &lt;a href=&#34;https://adventofcode.com/2023/day/5&#34;&gt;Day 5&lt;/a&gt; uses brute-force
and is not very clever, but runs fast enough in Go (under 6 minutes). The
&lt;a href=&#34;https://github.com/andreaskaempf/adventofcode/blob/main/2023/day05/main.rs&#34;&gt;Rust equivalent&lt;/a&gt;
runs in 1/3 less time, and I was wondering how other languages would fare.
The results might surprise you.&lt;/p&gt;
&lt;p&gt;I ended up writing the solution in
&lt;a href=&#34;https://github.com/andreaskaempf/adventofcode/blob/main/2023/day05/main.rs&#34;&gt;Rust&lt;/a&gt;,
&lt;a href=&#34;https://github.com/andreaskaempf/adventofcode/blob/main/2023/day05/zig/src/main.zig&#34;&gt;Zig&lt;/a&gt;, and
&lt;a href=&#34;https://github.com/andreaskaempf/adventofcode/blob/main/2023/day05/day05.c&#34;&gt;C&lt;/a&gt;,
in addition to the original
&lt;a href=&#34;https://github.com/andreaskaempf/adventofcode/blob/main/2023/day05/main.go&#34;&gt;Go solution&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The problem (at least my naive solution) is good for a language benchmark
because it involves lots of repeated transformations through a series
of logic steps, with math, logic, and branching/looping. It took 5:40
minutes in Go, and Rust brought that down to 3:45 (when compiled with
the &amp;ndash;release flag). The results for the four languages are interesting
(times in minutes):&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://fastdatascience.eu/images/blog/2024-10-18-times.png&#34; alt=&#34;Times&#34;&gt;&lt;/p&gt;
&lt;p&gt;Go takes 50% longer than Rust, better than I expected. As you&amp;rsquo;d expect, C is
faster than Rust, and at 2:40 by quite a margin (compiled using gcc with -O3
flag for optimizations, and clang did even better at 2:21). And the
big surprise was Zig, which ran in 1:51, using its ReleaseFast optimization
flag(i.e., &lt;code&gt;zig build -Doptimize=ReleaseFast&lt;/code&gt;).&lt;/p&gt;
&lt;h2 id=&#34;the-cost-of-speed-lines-of-code&#34; &gt;The cost of speed: lines of code?
&lt;span&gt;
    &lt;a href=&#34;#the-cost-of-speed-lines-of-code&#34;&gt;
        &lt;svg viewBox=&#34;0 0 28 23&#34; height=&#34;100%&#34; width=&#34;19&#34; xmlns=&#34;http://www.w3.org/2000/svg&#34;&gt;&lt;path d=&#34;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&#34; fill=&#34;none&#34; stroke-linecap=&#34;round&#34; stroke-miterlimit=&#34;10&#34; stroke-width=&#34;2&#34;/&gt;&lt;path d=&#34;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&#34; fill=&#34;none&#34; stroke-linecap=&#34;round&#34; stroke-miterlimit=&#34;10&#34; stroke-width=&#34;2&#34;/&gt;&lt;/svg&gt;
    &lt;/a&gt;
&lt;/span&gt;
&lt;/h2&gt;&lt;p&gt;Another comparison is lines of code. You&amp;rsquo;d expect Rust to require fewer lines
of code because of its expressive syntax, with function chaining, functional
programming (map, filter, etc.), macros and the like. This is indeed the
case. C and Zig are lower level, and require more lines (and programming time)
to produce results:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://fastdatascience.eu/images/blog/2024-10-18-lines.png&#34; alt=&#34;Lines of code&#34;&gt;&lt;/p&gt;
&lt;p&gt;However, you can see from a scatter plot of these two how Zig blows the other
languages out of the water from an execution time point of view, while requiring
almost 20% fewer lines than C, and roughly the same as Go:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://fastdatascience.eu/images/blog/2024-10-18-scatter.png&#34; alt=&#34;Lines vs time&#34;&gt;&lt;/p&gt;
&lt;p&gt;Note that these line counts exclude comments and blank lines.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Looking at Zig</title>
      <link>https://fastdatascience.eu/post/2024-10-13-look_at_zig/</link>
      <pubDate>Sun, 13 Oct 2024 00:00:00 +0000</pubDate>
      <guid>https://fastdatascience.eu/post/2024-10-13-look_at_zig/</guid>
      <description>&lt;p&gt;I finally took some time this weekend to look at Zig, and I am very impressed.
It&amp;rsquo;s a fairly low-level language, but could be appropriate for some
performance-critical data science use cases. Based on an initial test, it
is twice as fast as Rust, which is about 50% faster than Go. And it appears
to be faster than C, which I find puzzling.&lt;/p&gt;
&lt;p&gt;To explore the language, I rewrote a naive and computationally intensive
&lt;a href=&#34;https://github.com/andreaskaempf/adventofcode/blob/main/2023/day05/zig/src/main.zig&#34;&gt;brute-force solution&lt;/a&gt;
to &lt;a href=&#34;https://adventofcode.com/2023/day/5&#34;&gt;day 5&lt;/a&gt; of last year&amp;rsquo;s Advent of
Code. My non-sophisticated solution took 5:40 in Go for both parts, fast
enough that I didn&amp;rsquo;t bother finding a more streamlined solution (which
would have been necessary in Python). For comparison, I also rewrote the same solution in
&lt;a href=&#34;https://github.com/andreaskaempf/adventofcode/blob/main/2023/day05/main.rs&#34;&gt;Rust&lt;/a&gt; and
&lt;a href=&#34;https://github.com/andreaskaempf/adventofcode/blob/main/2023/day05/day05.c&#34;&gt;C&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;More on the performance comparisons in a future post. Here, I want to point out
some observations on the language, and some pointers on how to use it. I&amp;rsquo;m not
an experienced Zig user, so bear with me if you are.&lt;/p&gt;
&lt;h2 id=&#34;starting-a-project&#34; &gt;Starting a project
&lt;span&gt;
    &lt;a href=&#34;#starting-a-project&#34;&gt;
        &lt;svg viewBox=&#34;0 0 28 23&#34; height=&#34;100%&#34; width=&#34;19&#34; xmlns=&#34;http://www.w3.org/2000/svg&#34;&gt;&lt;path d=&#34;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&#34; fill=&#34;none&#34; stroke-linecap=&#34;round&#34; stroke-miterlimit=&#34;10&#34; stroke-width=&#34;2&#34;/&gt;&lt;path d=&#34;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&#34; fill=&#34;none&#34; stroke-linecap=&#34;round&#34; stroke-miterlimit=&#34;10&#34; stroke-width=&#34;2&#34;/&gt;&lt;/svg&gt;
    &lt;/a&gt;
&lt;/span&gt;
&lt;/h2&gt;&lt;p&gt;The Zig ecosystem can be installed from your package manager, e.g.,
&lt;code&gt;brew install zig&lt;/code&gt; on the Mac or &lt;code&gt;pacman -S zig&lt;/code&gt; on Arch Linux. You will also
want to install zls, the Zig Language Server, for IDE support.&lt;/p&gt;
&lt;p&gt;To create a new project, create a new folder, enter it and run &lt;code&gt;zig init&lt;/code&gt;. This creates
a src folder with a couple of zig files in it, and two build.zig files, which
control the build process.&lt;/p&gt;
&lt;p&gt;To compile, run &lt;code&gt;zig build&lt;/code&gt;, and the binary will be created in ./zig-out/bin and
you can run this directly, i.e., &lt;code&gt;zig-out/bin/test&lt;/code&gt;. When you&amp;rsquo;re ready, you
can compile with full optimizations by typing &lt;code&gt;zig build -Doptimization=ReleaseFast&lt;/code&gt;
and it is true to this promise, as we&amp;rsquo;ll see.&lt;/p&gt;
&lt;h2 id=&#34;the-language&#34; &gt;The language
&lt;span&gt;
    &lt;a href=&#34;#the-language&#34;&gt;
        &lt;svg viewBox=&#34;0 0 28 23&#34; height=&#34;100%&#34; width=&#34;19&#34; xmlns=&#34;http://www.w3.org/2000/svg&#34;&gt;&lt;path d=&#34;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&#34; fill=&#34;none&#34; stroke-linecap=&#34;round&#34; stroke-miterlimit=&#34;10&#34; stroke-width=&#34;2&#34;/&gt;&lt;path d=&#34;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&#34; fill=&#34;none&#34; stroke-linecap=&#34;round&#34; stroke-miterlimit=&#34;10&#34; stroke-width=&#34;2&#34;/&gt;&lt;/svg&gt;
    &lt;/a&gt;
&lt;/span&gt;
&lt;/h2&gt;&lt;p&gt;The Zig language looks a lot like C, but has more checks, and a type system
that looks a lot like Rust&amp;rsquo;s.  E.g., i32 and i64 for ints, etc.&lt;/p&gt;
&lt;p&gt;The big difference is that Zig is very &lt;strong&gt;picky about memory&lt;/strong&gt;, and you have to
manually allocate memory, and free it or the program will show a lot of errors
when it&amp;rsquo;s finished. So unlike Go, which does garbage collection to manage
memory automatically, and Rust, which compiles using a &amp;ldquo;borrow checker&amp;rdquo;
protocol that forces you to keep track of which variable currently &amp;ldquo;owns&amp;rdquo; each
value but then automatically deallocates it for you, Zig requires to to
allocate memory, and free it when you&amp;rsquo;re done.  I found this very tedious, but
it gets easier over time (as did the initially horrendous borrow checking in Rust).&lt;/p&gt;
&lt;p&gt;For example:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;//  Get a memory allocator
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
const allocator = gpa.allocator();
defer _ = gpa.deinit();

// Create a vector for numbers, add a number to it
var nums = std.ArrayList(i64).init(allocator);
try nums.append(5);

// Create a copy of a string
const my_name = &amp;quot;jabba the hut&amp;quot;;
const name = try std.mem.Allocator.dupe(allocator, u8, my_name);

// When finished, free up the list and string
nums.deinit();
allocator.free(name);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can &lt;strong&gt;free things up&lt;/strong&gt; when they go out of scope by using &lt;code&gt;defer&lt;/code&gt; as above, but
you have to be careful that these are no longer being used, as the compiler will
allow you to free things that have been passed to other variables (e.g., return
values from a function call). This approach led to some very time-consuming debugging.&lt;/p&gt;
&lt;p&gt;As noted, Zig has some useful data structures which are missing from C, but are present
in every modern language, such as vectors and hash maps. Everything in the standard library
is made available by importing one file, and is accessed by prefixing with &lt;code&gt;std.&lt;/code&gt; as shown here:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// At the beginning of every program
const std = @import(&amp;quot;std&amp;quot;);

// Use stdout for writing formatted output, note the arguments have to be 
// in a .{} list, don&#39;t forget the period
const stdout = std.io.getStdOut().writer();
try stdout.print(&amp;quot;A number {d} and a string {s}\n&amp;quot;, .{33, &amp;quot;hello&amp;quot;});

// Read a file into memory, automatically allocating space for it, up to 
// the size given, fails if the file is too big. Any data must be copied 
// if you want to use it after the buffer is freed when the function ends.
const data = try std.fs.cwd().readFileAlloc(allocator, &amp;quot;input.txt&amp;quot;, 10000);
defer allocator.free(data);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Functions&lt;/strong&gt; are central as you would expect, and programs are driven by a &lt;code&gt;main&lt;/code&gt; function
which calls other functions that take and return values:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;pub fn main() !void {
    try stdout.print(&amp;quot;{d} doubled is {d}\n&amp;quot;, .{12, double(12)});
}

fn double(n: i32) i32 {
    return n * 2;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You will notice that some function calls start with &lt;code&gt;try&lt;/code&gt; and some function return
types start with &lt;code&gt;!&lt;/code&gt;. This is because they might fail, and Zig&amp;rsquo;s &lt;strong&gt;error handling&lt;/strong&gt; is based
on return values that might be errors, just like in Rust. In Zig, &lt;code&gt;try&lt;/code&gt; executes the
function call, and raises an error if the call fails. The ! before the return type
indicates that the calling function might fail. It&amp;rsquo;s simple and quite elegant.&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;re interested, have a look at the
&lt;a href=&#34;https://github.com/andreaskaempf/adventofcode/blob/main/2023/day05/zig/src/main.zig&#34;&gt;AoC example&lt;/a&gt;,
the &lt;a href=&#34;https://ziglang.org/documentation/0.13.0/&#34;&gt;documentation&lt;/a&gt;, and the brief but excellent
&lt;a href=&#34;https://zig-by-example.com/&#34;&gt;Zig by Example&lt;/a&gt;. There are currently no books about Zig, but
that will change.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Local LLMs are getting easier</title>
      <link>https://fastdatascience.eu/post/2024-08-20-local_llms/</link>
      <pubDate>Fri, 23 Aug 2024 00:00:00 +0000</pubDate>
      <guid>https://fastdatascience.eu/post/2024-08-20-local_llms/</guid>
      <description>&lt;p&gt;There is increasing interest in using smaller large language models (LLMs),
hosted locally instead accessed from cloud-based vendors such as OpenAI.
My clients have been interested in these either from a cost point of view,
or for data protection reasons (since no data goes to OpenAI or other vendors).&lt;/p&gt;
&lt;p&gt;Although this has been done for a while from Python using (mainly) the excellent
&lt;a href=&#34;https://huggingface.co&#34;&gt;Hugging Face&lt;/a&gt;, new options have come available that
makes this easier and more flexible, especially from other languages such as Go
and Rust.  Here are observations and tips on a few alternatives that I&amp;rsquo;ve been
trying.&lt;/p&gt;
&lt;h2 id=&#34;ollama&#34; &gt;Ollama
&lt;span&gt;
    &lt;a href=&#34;#ollama&#34;&gt;
        &lt;svg viewBox=&#34;0 0 28 23&#34; height=&#34;100%&#34; width=&#34;19&#34; xmlns=&#34;http://www.w3.org/2000/svg&#34;&gt;&lt;path d=&#34;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&#34; fill=&#34;none&#34; stroke-linecap=&#34;round&#34; stroke-miterlimit=&#34;10&#34; stroke-width=&#34;2&#34;/&gt;&lt;path d=&#34;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&#34; fill=&#34;none&#34; stroke-linecap=&#34;round&#34; stroke-miterlimit=&#34;10&#34; stroke-width=&#34;2&#34;/&gt;&lt;/svg&gt;
    &lt;/a&gt;
&lt;/span&gt;
&lt;/h2&gt;&lt;p&gt;My favourite has been &lt;a href=&#34;https://ollama.com&#34;&gt;Ollama&lt;/a&gt;, a very clean and easy
to use open-source tool (written in Go!) that downloads a select number of
LLMs, then runs them, making available an input line for executing prompts,
as well as exposing an API that is similar to the one we are used to from
OpenAI.&lt;/p&gt;
&lt;p&gt;The tool can be downloaded from the &lt;a href=&#34;https://ollama.com/download&#34;&gt;web site&lt;/a&gt;,
and is easy to install on Mac OS and Linux. Then, just start it by typing
&lt;code&gt;ollama serve&lt;/code&gt; in a separate window.&lt;/p&gt;
&lt;p&gt;You first need to download one of the 50 or so supported models, listed
&lt;a href=&#34;https://ollama.com/library&#34;&gt;here&lt;/a&gt;. These include Llama 3.1 and 3.0, several
variants of Mistral, phi, and others. For example:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;ollama pull llama3.1&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Type &lt;code&gt;ollama list&lt;/code&gt; to see a list of models that have been downloaded (there
does not seem to be a command to list all available models, see the above
linked web page for that).&lt;/p&gt;
&lt;p&gt;As soon as a model is downloaded, run it with &lt;code&gt;ollama run llama3.1&lt;/code&gt; and it will
start up, with an input prompt that allows you to enter prompts.  Type &lt;code&gt;ollama info&lt;/code&gt; to show information about the model, such as the number of parameters and
context length.&lt;/p&gt;
&lt;p&gt;It also exposes an OpenAI-compatible API on port 11434, with endpoints
&lt;code&gt;generate&lt;/code&gt; and &lt;code&gt;chat&lt;/code&gt;, making this an easy option for calling the LLM for any
language using a REST API call. For example, from Go:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;package main

import (
	&amp;#34;encoding/json&amp;#34;
	&amp;#34;fmt&amp;#34;
	&amp;#34;io/ioutil&amp;#34;
	&amp;#34;net/http&amp;#34;
	&amp;#34;strings&amp;#34;
)

// Structure for a generate request
type Generate struct {
	Model  string `json:&amp;#34;model&amp;#34;`
	Prompt string `json:&amp;#34;prompt&amp;#34;`
}

// Structure of one token returned per line
type Token struct {
	Model     string `json:&amp;#34;model&amp;#34;`
	CreatedAt string `json:&amp;#34;created_at&amp;#34;`
	Response  string `json:&amp;#34;response&amp;#34;`
	Done      bool   `json:&amp;#34;done&amp;#34;`
}

func main() {

	// Parameters for the query
	prompt := &amp;#34;What is time?&amp;#34;
	model := &amp;#34;llama3&amp;#34;
	url := &amp;#34;http://localhost:11434/api/generate&amp;#34;

	// Formulate a request to generate response to prompt, as string
	msg := Generate{model, prompt}
	b, err := json.Marshal(msg)
	if err != nil {
		fmt.Println(err.Error())
		return
	}

	// Needs to be an io.Reader for the Post request
	data := strings.NewReader(string(b))

	// Make a POST request to the API
	response, err := http.Post(url, &amp;#34;application/json&amp;#34;, data)
	if err != nil {
		fmt.Println(err.Error())
		return
	}

	// Retrieve response
	responseData, err := ioutil.ReadAll(response.Body)
	if err != nil {
		fmt.Println(err.Error())
		return
	}

	// Extract and show individual tokens, one per line
	lines := strings.Split(string(responseData), &amp;#34;\n&amp;#34;)
	tokens := []string{}
	for _, l := range lines {

		// End of input
		if len(l) == 0 {
			break
		}

		// Parse JSON
		tkn := Token{}
		err := json.Unmarshal([]byte(l), &amp;amp;tkn)
		if err != nil {
			fmt.Println(err.Error())
			return
		}

		// Stop after final token
		if tkn.Done {
			break
		}

		// Add to list of tokens
		tokens = append(tokens, tkn.Response)
	}

	// Show result
	fmt.Println(tokens)
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Running this returns the following rather fanciful answer:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;What a profound and complex question!

Time is a fundamental concept in our experience of the universe, but its nature has puzzled philosophers, scientists, and scholars for centuries. Here&amp;#39;s an attempt to provide a comprehensive answer:

**Philosophical Perspectives:**

1. **Classical view:** Time is an objective feature of the universe, a linear progression from past to present to future. This perspective assumes time is a fixed, one-way dimension that governs our experience.
2. **Relational view:** Time is relative and dependent on the observer&amp;#39;s frame of reference. According to this perspective, time is not absolute, but rather an emergent property of physical laws and human perception.
3. **Subjective view:** Time is a subjective experience, shaped by individual experiences, emotions, and memories.

**Scientific Theories:**

1. **Newtonian Mechanics:** Time is an absolute concept, independent of the observer&amp;#39;s frame of reference. According to Newton&amp;#39;s laws, time flows at the same rate everywhere in the universe.
2. **Relativity Theory (Einstein):** Time and space are intertwined as a single entity called spacetime. The laws of physics are the same for all observers, regardless of their relative motion or position. Time can appear to pass differently depending on the observer&amp;#39;s frame of reference (e.g., time dilation).
3. **Quantum Mechanics:** Time is not a fixed dimension but rather an emergent property of quantum systems. Quantum phenomena, such as wave functions and entanglement, operate outside our classical understanding of time.

**Paradigm Shifts:**

1. **Kaluza-Klein Theory:** Higher-dimensional theories propose that our universe has more than the four dimensions we experience (three spatial and one temporal). This could imply that time is not an absolute concept.
2. **Fractal Time:** The idea that time is fractal, with repeating patterns at different scales, challenges our classical understanding of time as a linear progression.

**Philosophical Implications:**

1. **Free will vs. determinism:** If time is relative or subjective, does this imply free will, or are events predetermined?
2. **The nature of change:** Does the relativity of time imply that change is an illusion, or that reality is fundamentally dynamic?

**Conclusion:**

Time is a multifaceted concept that has been debated and explored across various disciplines. While our understanding of time has evolved significantly, the fundamental nature of time remains a subject of ongoing research and philosophical inquiry.

What&amp;#39;s your take on time? Do you have any questions or perspectives to share?
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Ollama also has options for importing GGUF files, creating models with a
built-in system prompt, and more. See the
&lt;a href=&#34;https://github.com/ollama/ollama&#34;&gt;GitHub page&lt;/a&gt; for more.&lt;/p&gt;
&lt;h2 id=&#34;llamafile&#34; &gt;LlamaFile
&lt;span&gt;
    &lt;a href=&#34;#llamafile&#34;&gt;
        &lt;svg viewBox=&#34;0 0 28 23&#34; height=&#34;100%&#34; width=&#34;19&#34; xmlns=&#34;http://www.w3.org/2000/svg&#34;&gt;&lt;path d=&#34;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&#34; fill=&#34;none&#34; stroke-linecap=&#34;round&#34; stroke-miterlimit=&#34;10&#34; stroke-width=&#34;2&#34;/&gt;&lt;path d=&#34;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&#34; fill=&#34;none&#34; stroke-linecap=&#34;round&#34; stroke-miterlimit=&#34;10&#34; stroke-width=&#34;2&#34;/&gt;&lt;/svg&gt;
    &lt;/a&gt;
&lt;/span&gt;
&lt;/h2&gt;&lt;p&gt;Another good alternative is
&lt;a href=&#34;https://github.com/Mozilla-Ocho/llamafile&#34;&gt;LlamaFile&lt;/a&gt;, which provides an
executable that contains the model inside it. To run this model, just download
one of the models from the web site, make it executable, and run it directly.&lt;/p&gt;
&lt;p&gt;This option exposes a web interface for exploring chats (at
http://localhost:8080), as well as an API compatible with the OpenAI one.&lt;/p&gt;
&lt;p&gt;This is an attractive way to explore local LLMs, but I have since found Ollama
easier to use and it offers a broader range of models.&lt;/p&gt;
&lt;h2 id=&#34;llamacpp&#34; &gt;LlamaCPP
&lt;span&gt;
    &lt;a href=&#34;#llamacpp&#34;&gt;
        &lt;svg viewBox=&#34;0 0 28 23&#34; height=&#34;100%&#34; width=&#34;19&#34; xmlns=&#34;http://www.w3.org/2000/svg&#34;&gt;&lt;path d=&#34;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&#34; fill=&#34;none&#34; stroke-linecap=&#34;round&#34; stroke-miterlimit=&#34;10&#34; stroke-width=&#34;2&#34;/&gt;&lt;path d=&#34;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&#34; fill=&#34;none&#34; stroke-linecap=&#34;round&#34; stroke-miterlimit=&#34;10&#34; stroke-width=&#34;2&#34;/&gt;&lt;/svg&gt;
    &lt;/a&gt;
&lt;/span&gt;
&lt;/h2&gt;&lt;p&gt;Most of the adaptions described above are derived from
&lt;a href=&#34;https://github.com/ggerganov/llama.cpp&#34;&gt;Llama.cpp&lt;/a&gt;, and amazing C++
program that loads and runs Llama and some other transformer models inside a
single program. It exposes both a web interface and an API. A large selections of models have been ported to this option.&lt;/p&gt;
&lt;p&gt;It is more fiddly than Ollama, because it requires you to separately obtain the
LLM in GGUF format, and specify this on the command line when running it. Most
GGUF models are available on Hugging Face, but it&amp;rsquo;s still an extra step with
some hassle.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ll create a separate post describing the running of LlamaCPP here, but you
can probably figure out from from the GitHub page linked above.&lt;/p&gt;
&lt;h2 id=&#34;candle&#34; &gt;Candle
&lt;span&gt;
    &lt;a href=&#34;#candle&#34;&gt;
        &lt;svg viewBox=&#34;0 0 28 23&#34; height=&#34;100%&#34; width=&#34;19&#34; xmlns=&#34;http://www.w3.org/2000/svg&#34;&gt;&lt;path d=&#34;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&#34; fill=&#34;none&#34; stroke-linecap=&#34;round&#34; stroke-miterlimit=&#34;10&#34; stroke-width=&#34;2&#34;/&gt;&lt;path d=&#34;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&#34; fill=&#34;none&#34; stroke-linecap=&#34;round&#34; stroke-miterlimit=&#34;10&#34; stroke-width=&#34;2&#34;/&gt;&lt;/svg&gt;
    &lt;/a&gt;
&lt;/span&gt;
&lt;/h2&gt;&lt;p&gt;Another interesting and ambitious option implemented in Rust is
&lt;a href=&#34;https://huggingface.github.io/candle/&#34;&gt;Candle&lt;/a&gt;, which supports about 20
models, and due to its support by Hugging Face is well documented and
supported.&lt;/p&gt;
&lt;p&gt;I plan on creating a separate post for this as I explore it further.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Advent of Code as a Lab for Fast Computing</title>
      <link>https://fastdatascience.eu/post/2023-11-16-aoc_favorites/</link>
      <pubDate>Sat, 16 Dec 2023 00:00:00 +0000</pubDate>
      <guid>https://fastdatascience.eu/post/2023-11-16-aoc_favorites/</guid>
      <description>&lt;p&gt;This year&amp;rsquo;s &lt;a href=&#34;https://adventofcode.com&#34;&gt;Advent of Code&lt;/a&gt; is well past
the half-way mark, and I&amp;rsquo;ve been reflecting on some of the harder or
more interesting problems over the last few years, and the lessons
learned about making code faster, or large problems tractable.&lt;/p&gt;
&lt;p&gt;In case you haven&amp;rsquo;t encountered it, AoC is an annual coding competition, with a
new problem every day, from December 1 through 25. Each day, there are two
parts, and the second (usually harder) part unlocks after you solve the first
part. You can use any programming language, and only need to submit the right
answer (usually a number) to solve each part.&lt;/p&gt;
&lt;p&gt;There is a global leaderboard, with amazingly short times for the top 100,
and my company also has an internal leaderboard. We have a chat channel
to share solutions and learnings, making it a very rich community
experience.&lt;/p&gt;
&lt;p&gt;The hardest problems for me have involved seeing things differently
in order to solve them. In many cases, Part 2 requires a better
algorithm, because while brute force may have sufficed for Part 1,
the second part is 100 or a million times bigger.&lt;/p&gt;
&lt;p&gt;I did these in a combination of Go, Julia, Rust, and Python. The code
for all my solutions for 2020 through 2024 are in
&lt;a href=&#34;https://github.com/andreaskaempf/adventofcode&#34;&gt;GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Here are some comments and observations about selected problems, with
a perspective on techniques that made large problems computable in a
reasonable amount of time.&lt;/p&gt;
&lt;h2 id=&#34;2021&#34; &gt;2021
&lt;span&gt;
    &lt;a href=&#34;#2021&#34;&gt;
        &lt;svg viewBox=&#34;0 0 28 23&#34; height=&#34;100%&#34; width=&#34;19&#34; xmlns=&#34;http://www.w3.org/2000/svg&#34;&gt;&lt;path d=&#34;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&#34; fill=&#34;none&#34; stroke-linecap=&#34;round&#34; stroke-miterlimit=&#34;10&#34; stroke-width=&#34;2&#34;/&gt;&lt;path d=&#34;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&#34; fill=&#34;none&#34; stroke-linecap=&#34;round&#34; stroke-miterlimit=&#34;10&#34; stroke-width=&#34;2&#34;/&gt;&lt;/svg&gt;
    &lt;/a&gt;
&lt;/span&gt;
&lt;/h2&gt;&lt;p&gt;&lt;strong&gt;Day 15&lt;/strong&gt; (Go, Julia): Find the lowest cost path through a graph, starting at
the top left, and ending up at the bottom right, adding up any cells you enter
along the path that minimizes total cost. I did this in Go using graph library,
Julia with Dijstra shortest-path algorithm (&lt;em&gt;medium&lt;/em&gt;). A great learning
experience for me, because it reinforced my application of when and how to use
graph algorithms. In general, simple graphs are easy and quick to search using
brute force, but larger graphs need algorithms to navigate quickly.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Day 19&lt;/strong&gt; (Go): Match up 3-dimensional cubes in space, adjusting x,y,z offset
and also rotation along any 3 axes, so that at least 12 points in the each pair
of cubes line up exactly. Then (Part 2), calculate the maximum distance between
the cubes (&lt;em&gt;hard&lt;/em&gt;). This problem required the right data structures to
represent shapes in space, which made the searching and measurement feasible
and quick.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Day 20&lt;/strong&gt; (Julia): Transform an image by successively replacing pixels with
values looked up from a translation table, the index being the value of the 9
cells surrounding each pixel, converted from binary to decimal. Much
complicated by the fact that the input data has a 1 in the first position of
the translation table, meaning that empty areas are filled with 1s, which muck
up the pixel count (&lt;em&gt;hard&lt;/em&gt;).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Day 21&lt;/strong&gt; (Go): Simulate a game of rolling dice and moving round a board,
trivial in Part 1. In Part 2, fork a set of parallel &amp;ldquo;universes&amp;rdquo; with identical
state after every throw of a 3-sided die, and get the number of universes in
which the winner won. This is one of the most head-breaking problems I&amp;rsquo;ve
encountered, required thinking about state in a different way (&lt;em&gt;hard&lt;/em&gt;).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Day 22&lt;/strong&gt; (Go): Turn on/off points in space, defined by 3-d ranges (like
rectangular cubes). Part 1 quite easy (basically used brute force), but for
Part 2 used recursive evaluation of volumes solution subtracting intersections.
This required thinking about space in a more abstract way, and basically
working backwards to get to an initial state (&lt;em&gt;hard&lt;/em&gt;).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Day 23&lt;/strong&gt; (Go): Find the most economical solution to a board game, involving 4
(later 8) pieces from random starting tunnels to ordered destination tunnels
via a corridor, sort of like the Towers of Hanoi. Solved the first part (8
pieces) on paper, second part using recursive depth-first search, eliminating
branches that exceeded best solution found so far. This was a breakthrough
for me in my understanding of Dynamic Programming (&lt;em&gt;hard&lt;/em&gt;).&lt;/p&gt;
&lt;h2 id=&#34;2022&#34; &gt;2022
&lt;span&gt;
    &lt;a href=&#34;#2022&#34;&gt;
        &lt;svg viewBox=&#34;0 0 28 23&#34; height=&#34;100%&#34; width=&#34;19&#34; xmlns=&#34;http://www.w3.org/2000/svg&#34;&gt;&lt;path d=&#34;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&#34; fill=&#34;none&#34; stroke-linecap=&#34;round&#34; stroke-miterlimit=&#34;10&#34; stroke-width=&#34;2&#34;/&gt;&lt;path d=&#34;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&#34; fill=&#34;none&#34; stroke-linecap=&#34;round&#34; stroke-miterlimit=&#34;10&#34; stroke-width=&#34;2&#34;/&gt;&lt;/svg&gt;
    &lt;/a&gt;
&lt;/span&gt;
&lt;/h2&gt;&lt;p&gt;&lt;strong&gt;Day 11&lt;/strong&gt; (Go, 100 lines): Simulate transfer of objects between a bunch of
monkeys, with &amp;ldquo;worry levels&amp;rdquo; assigned to each object. Each monkey modifies the
worry level according to some rules, then passes it to one of two monkeys,
depending on whether the worry level is divisible by that monkey&amp;rsquo;s &amp;ldquo;test&amp;rdquo;
number. Count up the number of inspections each monkey makes during the
simulation. The answer is the product of the two highest inspection counts.
Trivial (if tedious) for 20 iterations in Part 1, but integer values overflow
for 10,000 iterations in Part 2, unless you apply an adjustment that preserves
the decision outcomes while keeping the numbers fom getting too large. This
was one of numerous problems in AoC that required finding a work-around for
very large numbers (&lt;em&gt;hard&lt;/em&gt; for Part 2).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Day 13&lt;/strong&gt; (Python, 49 lines): Given pairs of nested lists of numbers, count up
how many are in the right order according to an arcane comparison function
(Part 1), then combine all the pair elements into one big list, add a couple of
marker elements, and sort the list according to the comparison function. For
Part 2, report the product of the indices of the two marker elements. This was
interesting because it&amp;rsquo;s quite easy in Python, due to its tolerance for
mixed types, and illustrates how different languages are better for different
things.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Day 15&lt;/strong&gt; (Go, 166 lines): Given a list of &amp;ldquo;sensors&amp;rdquo; and their distance to
nearest &amp;ldquo;beacon&amp;rdquo;, find positions in a row that could not possibly have a beacon
(Part 1), and the possible location of an undetected beacon (i.e., where there
is in coverage by known beacons) for Part 2. I did this one by mapping every
cell in the space, and it worked. But a colleague blew my mind with a very
short solution, that used a geospatial library that instantly solves this sort
of thing. Again, makes you reflect on which tool is best for every job
(&lt;em&gt;hard&lt;/em&gt;).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Day 16&lt;/strong&gt; (Go, also 166 lines): Given a network (graph) of closed &amp;ldquo;valves&amp;rdquo;, each
with a certain flow rate, connected by &amp;ldquo;tunnels&amp;rdquo;, find the sequence of opening
the valves (takes one minute, plus one minute per step to get there) that
yields the highest possible total flow during a 30-minute period. For Part 2,
same but try two decisions (one for you and one for the &amp;ldquo;elephant&amp;rdquo;) each time
step, over 26 minutes. Used simple depth-first dynamic programming solution,
recursively tries each feasible candidate unopened valve, excluding those for
which we wouldn&amp;rsquo;t have enough time to get any flow. Same for Part 2, but tried
all possible pairs of remaining valves, one for each actor (slow but works).
Some colleagues did this using linear programming (DP solution very &lt;em&gt;hard&lt;/em&gt;).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Day 17&lt;/strong&gt; (Go 123 lines + Python 87 lines): Simulate simple geometric shapes
falling down a shaft, getting moved left and right by gusts of &amp;ldquo;gas&amp;rdquo;, and
falling on top of each other. For Part 1, determine the total height of the
shapes after 2022 have fallen. For Part 2, do the same for 1 000 000 000 000
shapes (infeasible to simulate, so looked for repeating pattern in height
deltas, and applied simple math in separate Python script). This one was
&lt;em&gt;hard&lt;/em&gt;, but a breakthrough for me because it was infeasible to simulate, had to
find a way around this, which turned out to be detecting repeating cycles in
the output (which comes up regularly in AoC).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Day 18&lt;/strong&gt; (Go, 65 lines): Given a list of 1x1x1 cubes in 3-d space, count up
surfaces that don&amp;rsquo;t touch another point (Part 1). For Part 2, only count
surfaces that are outside the shape (may include some face inside of a
&amp;ldquo;tunnel&amp;rdquo;, so can&amp;rsquo;t just look outward from surface). I rated this one as &lt;em&gt;medium&lt;/em&gt;
difficuly at the time (and my solution is quite short), but I remember being
stretched by the need to think about space and anti-space.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Day 19&lt;/strong&gt; (Go, 152 lines): Basically a set of optimizations, to find the maximum
number of &amp;ldquo;geodes&amp;rdquo; that can be produced over 24 periods from a set of four
types of &amp;ldquo;robots&amp;rdquo;. Each robot can produce one mineral of its own kind each time
period. There are 30 &amp;ldquo;blueprints&amp;rdquo; (cost schedules), each of which lists the
number of each type of ingredient required to build a robot. So it&amp;rsquo;s a
production plan optimization. Part 1 asks you to optimize all 30 schedules,
Part 2 only the first 3 blueprints, but for 32 periods instead of 24 (&lt;em&gt;hard&lt;/em&gt;,
used dynamic programming but linear programming would have been possible).
This one was a real breakthrough for me in the application of Dynamic Programming,
including using recursion to break down a problem, and memoization to avoid
recomputing values already encountered.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Day 20&lt;/strong&gt; (Go, 95 lines): Given a list of numbers (7 in sample, but 5000 in
input), simulate moving each number forward or backward in the (circular) list,
forward if positive or backward if negative. For Part 1, do this once, and
report the sum of the values 1000, 2000, and 3000 after zero. For Part 2,
multiply each number by a huge value, and do it 10 times, report same sum.
Complicated by duplicate values in the main input, so you can&amp;rsquo;t just look for
position of a value. Also, iterations in Part 2 are infeasible with large
multiplier as well as 10 iterations (&lt;em&gt;hard&lt;/em&gt;). This one was a breakthrough for
me because it highlighted the importance of using the right data structure,
in this case a circular queue.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Day 21&lt;/strong&gt; (Go, 72 lines): Given a list of variable names, each with either a
numbers or a simple formula, recursively evaluate the root node (Part 1), and
find the value for one cell that makes the two sides of the root node equal.
This one was only &lt;em&gt;medium&lt;/em&gt; difficulty for me, but I remember having the &amp;ldquo;aha&amp;rdquo;
moment when I realized that it could be solved using gradient descent, which
I have several times coded during my career.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Day 22&lt;/strong&gt; (Go, 374 lines): Simulate movement on a 2D map, according to a list of
instructions, which can either be to move n steps, or to turn 90 degrees left
or right. There are obstacles to avoid, and one wraps around to the other side
when walking off and edge. For Part 1, the map is in 2D. For Part 3, the map
gets folded into a cube. This one was very &lt;em&gt;hard&lt;/em&gt;, because of the 2D movements
on different contiguous surfaces of a 3D object. I created a very verbose
solution that mapped each possible transition from one surface to another.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Day 24&lt;/strong&gt; (Go, 175 lines): Find shortest path from entry to exit of a rectangular
field, avoiding &amp;ldquo;blizzards&amp;rdquo; that move every time step. For Part 2, also move
back to entry then back to exit, and add up all the steps. Used dynamic
programming, depth-first search with memoization of previously found best
values for each position+time combination (&lt;em&gt;medium&lt;/em&gt;). Again a problem that
reinforced my understanding and appreciation of Dynamic Programming.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Linear Programming in Go</title>
      <link>https://fastdatascience.eu/post/2023-11-12-linear_programming_in_go/</link>
      <pubDate>Sun, 12 Nov 2023 00:00:00 +0000</pubDate>
      <guid>https://fastdatascience.eu/post/2023-11-12-linear_programming_in_go/</guid>
      <description>&lt;p&gt;I&amp;rsquo;ve been away helping Bain set up a new capability in generative AI,
on the back of our &lt;a href=&#34;https://www.openai.com&#34;&gt;OpenAI&lt;/a&gt; partnership, and
am coming back to standard data science problems. In this post, I&amp;rsquo;d
like to share some experiments doing linear programming optimization,
using Gonum&amp;rsquo;s optimization library. It&amp;rsquo;s a very basic facility, but has
helped me learn how to set up problems using the venerable
&lt;a href=&#34;https://en.wikipedia.org/wiki/Simplex_algorithm&#34;&gt;Simplex algorithm&lt;/a&gt;,
first developed by George Danzig in 1947.&lt;/p&gt;
&lt;p&gt;First of all, I wouldn&amp;rsquo;t recommend using this approach for real problem
solving, since it&amp;rsquo;s rather cumbersome, as you will see. Instead, use
&lt;a href=&#34;https://github.com/coin-or/pulp&#34;&gt;Pulp&lt;/a&gt; or another Python library, or
a dedicated mathematical programming tool such as
&lt;a href=&#34;https://www.gnu.org/software/glpk/&#34;&gt;GLPK&lt;/a&gt; (open source) or
&lt;a href=&#34;https://www.gurobi.com&#34;&gt;Gurobi&lt;/a&gt; (commercial license). Nevertheless, I
found this approach helpful for finally understanding how problems are
represented as matrices, and it serves as a readily available, minimalist
approach to solving simpler linear optimization problems.&lt;/p&gt;
&lt;h2 id=&#34;a-simple-problem&#34; &gt;A simple problem
&lt;span&gt;
    &lt;a href=&#34;#a-simple-problem&#34;&gt;
        &lt;svg viewBox=&#34;0 0 28 23&#34; height=&#34;100%&#34; width=&#34;19&#34; xmlns=&#34;http://www.w3.org/2000/svg&#34;&gt;&lt;path d=&#34;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&#34; fill=&#34;none&#34; stroke-linecap=&#34;round&#34; stroke-miterlimit=&#34;10&#34; stroke-width=&#34;2&#34;/&gt;&lt;path d=&#34;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&#34; fill=&#34;none&#34; stroke-linecap=&#34;round&#34; stroke-miterlimit=&#34;10&#34; stroke-width=&#34;2&#34;/&gt;&lt;/svg&gt;
    &lt;/a&gt;
&lt;/span&gt;
&lt;/h2&gt;&lt;p&gt;Here is a simple example LP problem, from
&lt;a href=&#34;http://people.brunel.ac.uk/~mastjjb/jeb/or/morelp.html&#34;&gt;Brunel University&lt;/a&gt;:&lt;/p&gt;
&lt;p&gt;&lt;em&gt;A company is involved in the production of two items (X and Y). The
resources need to produce X and Y are twofold, namely machine time for
automatic processing and craftsman time for hand finishing. The table below
gives the number of minutes required for each item:&lt;/em&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;         Machine time Craftsman time
Item X   13           20
     Y   19           29
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;em&gt;The company has 40 hours of machine time available in the next working week
but only 35 hours of craftsman time. Machine time is costed at £10 per hour
worked and craftsman time is costed at £2 per hour worked. Both machine and
craftsman idle times incur no costs. The revenue received for each item
produced (all production is sold) is £20 for X and £30 for Y. The company
has a specific contract to produce 10 items of X per week for a particular
customer.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id=&#34;formulating-the-problem&#34; &gt;Formulating the problem
&lt;span&gt;
    &lt;a href=&#34;#formulating-the-problem&#34;&gt;
        &lt;svg viewBox=&#34;0 0 28 23&#34; height=&#34;100%&#34; width=&#34;19&#34; xmlns=&#34;http://www.w3.org/2000/svg&#34;&gt;&lt;path d=&#34;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&#34; fill=&#34;none&#34; stroke-linecap=&#34;round&#34; stroke-miterlimit=&#34;10&#34; stroke-width=&#34;2&#34;/&gt;&lt;path d=&#34;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&#34; fill=&#34;none&#34; stroke-linecap=&#34;round&#34; stroke-miterlimit=&#34;10&#34; stroke-width=&#34;2&#34;/&gt;&lt;/svg&gt;
    &lt;/a&gt;
&lt;/span&gt;
&lt;/h2&gt;&lt;p&gt;A simple formulation to this problem into decision variables, objective
function, and constraints, looks as follows:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Let
    x be the number of items of X
    y be the number of items of Y

Maximise
    20x + 30y - 10(machine time worked) - 2(craftsman time worked)

Subject to:
    13x + 19y &amp;lt;= 2400       // machine time
    20x + 29y &amp;lt;= 2100       // craftsman time
    x &amp;gt;= 10                 // contract
    x,y &amp;gt;= 0
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The objective function can be expanded and simplified as:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Maximise
    20x + 30y - 10(13x + 19y)/60 - 2(20x + 29y)/60
    =&amp;gt; 17.1667x + 25.8667y
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&#34;converting-to-matrix&#34; &gt;Converting to matrix
&lt;span&gt;
    &lt;a href=&#34;#converting-to-matrix&#34;&gt;
        &lt;svg viewBox=&#34;0 0 28 23&#34; height=&#34;100%&#34; width=&#34;19&#34; xmlns=&#34;http://www.w3.org/2000/svg&#34;&gt;&lt;path d=&#34;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&#34; fill=&#34;none&#34; stroke-linecap=&#34;round&#34; stroke-miterlimit=&#34;10&#34; stroke-width=&#34;2&#34;/&gt;&lt;path d=&#34;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&#34; fill=&#34;none&#34; stroke-linecap=&#34;round&#34; stroke-miterlimit=&#34;10&#34; stroke-width=&#34;2&#34;/&gt;&lt;/svg&gt;
    &lt;/a&gt;
&lt;/span&gt;
&lt;/h2&gt;&lt;p&gt;The above formulation can be input almost verbatim into the various
standard optimization libraries (example below). To use Gonum&amp;rsquo;s simplex
optimizer, however, you need to convert it to a matrix. This process
is &lt;em&gt;not described&lt;/em&gt; in the documentation, and I could not find any pages
that show examples with explanation. So here we go.&lt;/p&gt;
&lt;p&gt;The call to the optimizer will look like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;opt, x, err := lp.Simplex(c, A, b, 0, nil)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;There are three important arguments to Simplex:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;c&lt;/strong&gt; is a vector (array of float64 numbers) of the &lt;strong&gt;objective function&lt;/strong&gt;
coefficients (negative to minimize)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;A&lt;/strong&gt; is a matrix of the left hand side &lt;strong&gt;coefficients for the constraints&lt;/strong&gt;,
one row per constraint&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;b&lt;/strong&gt; is a vector of the right hand side values of the constraints&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Let&amp;rsquo;s take them in turn.&lt;/p&gt;
&lt;h3 id=&#34;objective-function-coefficients&#34; &gt;Objective function coefficients
&lt;span&gt;
    &lt;a href=&#34;#objective-function-coefficients&#34;&gt;
        &lt;svg viewBox=&#34;0 0 28 23&#34; height=&#34;100%&#34; width=&#34;19&#34; xmlns=&#34;http://www.w3.org/2000/svg&#34;&gt;&lt;path d=&#34;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&#34; fill=&#34;none&#34; stroke-linecap=&#34;round&#34; stroke-miterlimit=&#34;10&#34; stroke-width=&#34;2&#34;/&gt;&lt;path d=&#34;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&#34; fill=&#34;none&#34; stroke-linecap=&#34;round&#34; stroke-miterlimit=&#34;10&#34; stroke-width=&#34;2&#34;/&gt;&lt;/svg&gt;
    &lt;/a&gt;
&lt;/span&gt;
&lt;/h3&gt;&lt;p&gt;The &lt;strong&gt;objective function&lt;/strong&gt; is&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Maximise:
    17.1667x + 25.8667y
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;There are only two decision variables (x and y), so we are only interested
in two columns here. However, we need to add &lt;em&gt;three more columns&lt;/em&gt; for the
&amp;ldquo;slack&amp;rdquo; variables, one per constraint, otherwise there will be no
feasible solution if the optimum values do not exactly equal the constraints.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; &lt;em&gt;can we make do with two slack variables, one per decision variable
(x and y) instead of one for each of the three constraints?&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Furthermore, the Simplex algorithm does &lt;em&gt;minimization&lt;/em&gt;, so to maximize,
we need to multiply the coefficents by -1.&lt;/p&gt;
&lt;p&gt;So &lt;strong&gt;c&lt;/strong&gt;, our vector for the objective function coefficients, is:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;c := []float64{-17.2, -25.9, 0, 0, 0}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&#34;lhs-constraint-coefficients&#34; &gt;LHS constraint coefficients
&lt;span&gt;
    &lt;a href=&#34;#lhs-constraint-coefficients&#34;&gt;
        &lt;svg viewBox=&#34;0 0 28 23&#34; height=&#34;100%&#34; width=&#34;19&#34; xmlns=&#34;http://www.w3.org/2000/svg&#34;&gt;&lt;path d=&#34;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&#34; fill=&#34;none&#34; stroke-linecap=&#34;round&#34; stroke-miterlimit=&#34;10&#34; stroke-width=&#34;2&#34;/&gt;&lt;path d=&#34;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&#34; fill=&#34;none&#34; stroke-linecap=&#34;round&#34; stroke-miterlimit=&#34;10&#34; stroke-width=&#34;2&#34;/&gt;&lt;/svg&gt;
    &lt;/a&gt;
&lt;/span&gt;
&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;A&lt;/strong&gt; is a Gonum matrix of the left hand side &lt;strong&gt;coefficients for the
constraints&lt;/strong&gt;. There is one row per constraint. There is also one
column per decision variable (x and y), but also additional columns
with diagonal ones, one per constraint.&lt;/p&gt;
&lt;p&gt;Note that&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&amp;lt;= constraints are converted to = by adding slack variables&lt;/li&gt;
&lt;li&gt;&amp;lt;= constraints are represented with the same sign as the problem definition&lt;/li&gt;
&lt;li&gt;Any &amp;gt;= constraints need to have the coefficients multiplied by -1, both in the
left hand side (matrix A), and also the vector of right-hand side values
(c, see below)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Our constraints are:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Subject to:
    13x + 19y &amp;lt;= 2400       // machine time
    20x + 29y &amp;lt;= 2100       // craftsman time
    x &amp;gt;= 10                 // contract
    x,y &amp;gt;= 0
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The matrix is 3 rows x 5 columns (note that x,y &amp;gt;= 0 does not need to
expressed, as the algorithm takes care of this constraint):&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;13 19  1  0  0
20 29  0  1  0
-1  0  0  0  1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The first row is 13x + 19y, the second row is 20x + 20y, and the third row
is 1x (converted to negative because it is &amp;gt;= instead of &amp;lt;=).&lt;/p&gt;
&lt;p&gt;The Go matrix (using Gonum&amp;rsquo;s mat module) is:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;A := mat.NewDense(3, 5, []float64{
    13, 19, 1, 0, 0,
    20, 29, 0, 1, 0,
    -1, 0, 0, 0, 1})
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&#34;right-hand-constraint-values&#34; &gt;Right hand constraint values
&lt;span&gt;
    &lt;a href=&#34;#right-hand-constraint-values&#34;&gt;
        &lt;svg viewBox=&#34;0 0 28 23&#34; height=&#34;100%&#34; width=&#34;19&#34; xmlns=&#34;http://www.w3.org/2000/svg&#34;&gt;&lt;path d=&#34;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&#34; fill=&#34;none&#34; stroke-linecap=&#34;round&#34; stroke-miterlimit=&#34;10&#34; stroke-width=&#34;2&#34;/&gt;&lt;path d=&#34;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&#34; fill=&#34;none&#34; stroke-linecap=&#34;round&#34; stroke-miterlimit=&#34;10&#34; stroke-width=&#34;2&#34;/&gt;&lt;/svg&gt;
    &lt;/a&gt;
&lt;/span&gt;
&lt;/h3&gt;&lt;p&gt;Finally, &lt;strong&gt;b&lt;/strong&gt; is a vector of the right hand side values of the constraints,
the bounds to which we are restricting the various constraints.&lt;/p&gt;
&lt;p&gt;Again, given these constraints:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Subject to:
    13x + 19y &amp;lt;= 2400       // machine time
    20x + 29y &amp;lt;= 2100       // craftsman time
    x &amp;gt;= 10                 // contract
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The bounds are 2400, 2100, and 10. But the 10 needs to be -10, since it
is a &amp;gt;= instead of &amp;lt;= constraint. So the Go array is:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;b := []float64{2400, 2100, -10}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&#34;putting-it-all-together&#34; &gt;Putting it all together
&lt;span&gt;
    &lt;a href=&#34;#putting-it-all-together&#34;&gt;
        &lt;svg viewBox=&#34;0 0 28 23&#34; height=&#34;100%&#34; width=&#34;19&#34; xmlns=&#34;http://www.w3.org/2000/svg&#34;&gt;&lt;path d=&#34;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&#34; fill=&#34;none&#34; stroke-linecap=&#34;round&#34; stroke-miterlimit=&#34;10&#34; stroke-width=&#34;2&#34;/&gt;&lt;path d=&#34;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&#34; fill=&#34;none&#34; stroke-linecap=&#34;round&#34; stroke-miterlimit=&#34;10&#34; stroke-width=&#34;2&#34;/&gt;&lt;/svg&gt;
    &lt;/a&gt;
&lt;/span&gt;
&lt;/h2&gt;&lt;p&gt;The complete program looks as follows:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;package main

import (
    &amp;quot;fmt&amp;quot;
    &amp;quot;gonum.org/v1/gonum/mat&amp;quot;
    &amp;quot;gonum.org/v1/gonum/optimize/convex/lp&amp;quot;
)

func main() {

    // Problem formulation
    c := []float64{-17.2, -25.9, 0, 0, 0}
    A := mat.NewDense(3, 5, []float64{
        13, 19, 1, 0, 0,
        20, 29, 0, 1, 0,
        -1, 0, 0, 0, 1})
    b := []float64{2400, 2100, -10}

    // Run Simplex algorithm, last parameter is initialBasic
    opt, x, err := lp.Simplex(c, A, b, 0, nil)
    if err != nil {
        fmt.Println(err.Error())
        return
    }

    fmt.Printf(&amp;quot;Optimum = %f, x = %f, y = %f\n&amp;quot;, opt, x[0], x[1])
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Note that in addition to c, A, and b, lp.Simplex also requires a number
as the tolerance (0 as in the example above), and optionally a vector
representing the starting values.&lt;/p&gt;
&lt;p&gt;Also note that lp.Simplex returns the optimum value, an array of coefficients,
and an error (e.g., solution is infeasible, or problem is unbounded). The
array of solution coefficients corresponds to the columns in the A matrix,
so you only need to the first two in the example above (altough the others
are interesting for seeing the slack values).&lt;/p&gt;
&lt;p&gt;You will need to install Gonum&amp;rsquo;s matrix and simplex modules:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;go get gonum.org/v1/gonum
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So to build and run the program, do the following:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;mkdir lpexample
cd lpexample
vim main.go
(paste the above code and save)
go mod init lpexample
go get gonum.org/v1/gonum
go build
./lpexample
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You should get the solution x = 10, y = 65.52, max = 1866.5&lt;/p&gt;
&lt;h2 id=&#34;formulation-in-python&#34; &gt;Formulation in Python
&lt;span&gt;
    &lt;a href=&#34;#formulation-in-python&#34;&gt;
        &lt;svg viewBox=&#34;0 0 28 23&#34; height=&#34;100%&#34; width=&#34;19&#34; xmlns=&#34;http://www.w3.org/2000/svg&#34;&gt;&lt;path d=&#34;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&#34; fill=&#34;none&#34; stroke-linecap=&#34;round&#34; stroke-miterlimit=&#34;10&#34; stroke-width=&#34;2&#34;/&gt;&lt;path d=&#34;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&#34; fill=&#34;none&#34; stroke-linecap=&#34;round&#34; stroke-miterlimit=&#34;10&#34; stroke-width=&#34;2&#34;/&gt;&lt;/svg&gt;
    &lt;/a&gt;
&lt;/span&gt;
&lt;/h2&gt;&lt;p&gt;As mentionned above, such programs are much easier to create and understand
using a Python library or a dedicated mathematical programming tool. For
comparison, below is the same problem formulated in Python
using &lt;a href=&#34;https://github.com/coin-or/pulp&#34;&gt;Pulp&lt;/a&gt;.  It&amp;rsquo;s a bit
longer, but easier to read and maintain, because you don&amp;rsquo;t need
to keep track of the columns and signs in the matrices and vectors. It also
allows you to switch between different solvers.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;from pulp import *

# Create the &#39;prob&#39; variable to contain the problem data
prob = LpProblem(&amp;quot;Example&amp;quot;, LpMaximize)

# Problem variables (use LpInteger for integer solution)
x = LpVariable(&amp;quot;x&amp;quot;, 0, None, LpContinuous)
y = LpVariable(&amp;quot;y&amp;quot;, 0, None, LpContinuous)

# Objective function
prob += 17.2*x + 25.9*y

# Constraints
prob += 13*x + 19*y &amp;lt;= 2400 # machine time constraint
prob += 20*x + 29*y &amp;lt;= 2100 # labor time constraint
prob += x &amp;gt;= 10 # contract commitment

# Solve the problem
status = prob.solve()

# Print results
print(&amp;quot;Status:&amp;quot;, LpStatus[status])
print(&amp;quot;x:&amp;quot;, value(x))
print(&amp;quot;y:&amp;quot;, value(y))
print(&amp;quot;Objective:&amp;quot;, value(prob.objective))
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Again, you should get the solution x = 10, y = 65.52, max = 1866.5 (or slightly
different if you chose to use LpInteger for integer programming).&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Starting a New Go Project</title>
      <link>https://fastdatascience.eu/post/2022-06-30-new_go_project/</link>
      <pubDate>Thu, 30 Jun 2022 00:00:00 +0000</pubDate>
      <guid>https://fastdatascience.eu/post/2022-06-30-new_go_project/</guid>
      <description>&lt;p&gt;If you are new to Go, here is the basic process for setting up a new project
and building/running it. This assumes that you have already installed Go as
described in the &lt;a href=&#34;https://fastdatascience.eu/post/2022-06-19-basic_go_setup/&#34;&gt;previous blog post&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;First, &lt;strong&gt;create a working directory&lt;/strong&gt; for the project, and change into it:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;mkdir ~/myproject
cd ~/myproject
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, use your favorite text editor or IDE to &lt;strong&gt;create a Go program&lt;/strong&gt;, with any
name that ends in .go, for example main.go:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;vim main.go
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here is the canonical simplest program, that just prints a message:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;package main

import &amp;quot;fmt&amp;quot;

func main() {
    fmt.Println(&amp;quot;Welcome to Go&amp;quot;)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You could &lt;strong&gt;compile this program directly&lt;/strong&gt;, by typing:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;go build main.go
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, you will see a new file called &lt;em&gt;main&lt;/em&gt; in the directory, and you can
&lt;strong&gt;run this executable&lt;/strong&gt; by typing:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;./main
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;However, I recommend that you &lt;strong&gt;set up the program as a module&lt;/strong&gt;, so you can
use &lt;code&gt;go build&lt;/code&gt; to build a program from multiple source files, and run tests.
This also plays nicely with IDEs:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;go mod init fastdatascience.io/myprogram
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Replace the URL with your own (or with github.com if creating an open-source
module that others can pull in). The module name (&amp;ldquo;myprogram&amp;rdquo; in the example
above) should be the same name as the directory, so IDEs like LiteIDE will
build correctly. Note the URL is optional, and you don&amp;rsquo;t need the slash if
you omit the URL.&lt;/p&gt;
&lt;p&gt;Then, you can just type:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;go build
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;to create the executable. As before type &lt;code&gt;./main&lt;/code&gt; to run the program.&lt;/p&gt;
&lt;p&gt;You can also type &lt;code&gt;go run&lt;/code&gt; to build and run the program in one step (but
this does not keep the executable).&lt;/p&gt;
&lt;p&gt;Finally, you should initialize the directory with Git and make a commit
with you your new program:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;git init
git add main.go
git commit -a -m &amp;quot;Initial commit of new Go program
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can also create a respository in GitHub, and sync the repository
to to GitHub.&lt;/p&gt;
&lt;p&gt;That&amp;rsquo;s it, you now have a project to build upon.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>A Basic Go Setup</title>
      <link>https://fastdatascience.eu/post/2022-06-19-basic_go_setup/</link>
      <pubDate>Sun, 19 Jun 2022 00:00:00 +0000</pubDate>
      <guid>https://fastdatascience.eu/post/2022-06-19-basic_go_setup/</guid>
      <description>&lt;p&gt;In this article, I wanted to share the setup I use for writing data
science programs in &lt;a href=&#34;https://go.dev&#34;&gt;Go&lt;/a&gt;. I&amp;rsquo;ve found it very easy to
get started with this language, but thought it might be useful to
describe the setup.&lt;/p&gt;
&lt;p&gt;I use both Linux and a Mac, so this article will describe those platforms, but
Go should work well on Windows as well. In any case, we assume that you are
comfortable running the command line.&lt;/p&gt;
&lt;h2 id=&#34;installing-the-go-compiler-and-tools&#34; &gt;Installing the Go compiler and tools
&lt;span&gt;
    &lt;a href=&#34;#installing-the-go-compiler-and-tools&#34;&gt;
        &lt;svg viewBox=&#34;0 0 28 23&#34; height=&#34;100%&#34; width=&#34;19&#34; xmlns=&#34;http://www.w3.org/2000/svg&#34;&gt;&lt;path d=&#34;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&#34; fill=&#34;none&#34; stroke-linecap=&#34;round&#34; stroke-miterlimit=&#34;10&#34; stroke-width=&#34;2&#34;/&gt;&lt;path d=&#34;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&#34; fill=&#34;none&#34; stroke-linecap=&#34;round&#34; stroke-miterlimit=&#34;10&#34; stroke-width=&#34;2&#34;/&gt;&lt;/svg&gt;
    &lt;/a&gt;
&lt;/span&gt;
&lt;/h2&gt;&lt;p&gt;First of all, install Go itself. On Linux, use your package manager, e.g.,
on Arch Linux it would be:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;pacman -S go
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;On Mac OS, you can either use Homebrew:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;brew install go
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Or download and run the installer from &lt;a href=&#34;https://go.dev/dl&#34;&gt;https://go.dev/dl&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Either way, you should be able to run the go program to get the version, e.g.,&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;go version
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&#34;choosing-an-editor-or-ide&#34; &gt;Choosing an editor or IDE
&lt;span&gt;
    &lt;a href=&#34;#choosing-an-editor-or-ide&#34;&gt;
        &lt;svg viewBox=&#34;0 0 28 23&#34; height=&#34;100%&#34; width=&#34;19&#34; xmlns=&#34;http://www.w3.org/2000/svg&#34;&gt;&lt;path d=&#34;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&#34; fill=&#34;none&#34; stroke-linecap=&#34;round&#34; stroke-miterlimit=&#34;10&#34; stroke-width=&#34;2&#34;/&gt;&lt;path d=&#34;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&#34; fill=&#34;none&#34; stroke-linecap=&#34;round&#34; stroke-miterlimit=&#34;10&#34; stroke-width=&#34;2&#34;/&gt;&lt;/svg&gt;
    &lt;/a&gt;
&lt;/span&gt;
&lt;/h2&gt;&lt;p&gt;Go programs are just text files, so you can use any editor. Many editors
have plug-ins to support Go programming, so you will want to look into
these. I use &lt;a href=&#34;https://vim.org&#34;&gt;vim&lt;/a&gt;, and have found
&lt;a href=&#34;https://github.com/govim/govim&#34;&gt;go-vim&lt;/a&gt; quite useful.&lt;/p&gt;
&lt;p&gt;If you like something bigger, &lt;a href=&#34;https://go.dev/doc/editors&#34;&gt;this page&lt;/a&gt;
describes various Integrated Development Environments (IDEs). The most
widely used seem to be &lt;a href=&#34;https://code.visualstudio.com/&#34;&gt;VS Code&lt;/a&gt; (free
but not open source) with
&lt;a href=&#34;https://code.visualstudio.com/docs/languages/go&#34;&gt;this extension&lt;/a&gt;,
and &lt;a href=&#34;https://www.jetbrains.com/go/&#34;&gt;GoLand&lt;/a&gt; (commercial product requiring
a paid license) from JetBrains, the makers of PyCharm for Python.&lt;/p&gt;
&lt;p&gt;And &lt;strong&gt;my favorite option&lt;/strong&gt; has become &lt;a href=&#34;http://liteide.org&#34;&gt;LiteIDE&lt;/a&gt;, a
simple and small open-source IDE specifically for Go. It can be downloaded
and installed from the above link (or using your package manager on Linux).
I like LiteIDE&amp;rsquo;s simple project architecture (just a directory containing
code), debugging support, and simple interface, which has buttons to
build, run, and test your code.&lt;/p&gt;
&lt;p&gt;In the &lt;a href=&#34;https://fastdatascience.eu/post/2022-06-30-new_go_project&#34;&gt;next post&lt;/a&gt;, I&amp;rsquo;ll assume you&amp;rsquo;ve set up
Go and your favorite editor or IDE, and will describe how to create and run a
simple program.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Why Speed Matters</title>
      <link>https://fastdatascience.eu/post/2022-05-08-why_speed_matters/</link>
      <pubDate>Sun, 08 May 2022 00:00:00 +0000</pubDate>
      <guid>https://fastdatascience.eu/post/2022-05-08-why_speed_matters/</guid>
      <description>&lt;p&gt;The vast bulk of data science work is done using &lt;a href=&#34;https://python.org&#34;&gt;Python&lt;/a&gt;
and &lt;a href=&#34;https://www.r-project.org&#34;&gt;R&lt;/a&gt;, and that&amp;rsquo;s fine. Those languages are
well suited to analytics, and make available a rich infrastucture of libraries
and documentation.&lt;/p&gt;
&lt;p&gt;Looking at just Python (R is similar), there is however a problem. Python is
&lt;em&gt;slow&lt;/em&gt;, due to its interpreted execution model and dynamic typing. As a Python
program runs, it is constantly checking for the types of different variables
and data, and for the feasibility of certain operations such as converting
data types and expanding lists. While this makes for fast development and
prototyping, it can be very slow for some types of analysis.&lt;/p&gt;
&lt;p&gt;The penny dropped for me after I worked on a price optimization project for
a global beer company, which optimized wholesale and retail prices across
four countries, partly using complex procedural logic to calculate the
impact of price changes on volume. The Python optimization was done using
simulated annealing, using the standard scikit-learn library. The optimization
took &lt;em&gt;twelve minutes&lt;/em&gt; to run, and defeated our hopes of running it in real
time behind an interactive user interface.&lt;/p&gt;
&lt;p&gt;The problem was that the objective function (which needs to run hundreds or
thousands of times as the optimization explores the solution space) consisted
of about 200 lines of Python. While the simulated annealing was presumably
efficient, this complex objective function code made the optimization a
slow process.&lt;/p&gt;
&lt;h2 id=&#34;discovering-alternatives&#34; &gt;Discovering Alternatives
&lt;span&gt;
    &lt;a href=&#34;#discovering-alternatives&#34;&gt;
        &lt;svg viewBox=&#34;0 0 28 23&#34; height=&#34;100%&#34; width=&#34;19&#34; xmlns=&#34;http://www.w3.org/2000/svg&#34;&gt;&lt;path d=&#34;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&#34; fill=&#34;none&#34; stroke-linecap=&#34;round&#34; stroke-miterlimit=&#34;10&#34; stroke-width=&#34;2&#34;/&gt;&lt;path d=&#34;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&#34; fill=&#34;none&#34; stroke-linecap=&#34;round&#34; stroke-miterlimit=&#34;10&#34; stroke-width=&#34;2&#34;/&gt;&lt;/svg&gt;
    &lt;/a&gt;
&lt;/span&gt;
&lt;/h2&gt;&lt;p&gt;During some vacation after the project, I took advantage of the down-time
to learn &lt;a href=&#34;https://julialang.org&#34;&gt;Julia&lt;/a&gt;. As a specific project, I rewrote the
optimization in Julia, using its optional static typing, and an open-source
simulated annealing libary, and the execution time went from &lt;em&gt;twelve minutes
down to six seconds&lt;/em&gt;.  This massive speed improvement (a factor of 120x),
brought the idea of a user interface running the simulation in the background
into the realm of
possibility.&lt;/p&gt;
&lt;p&gt;A few months later, I decided to learn &lt;a href=&#34;https://go.dev&#34;&gt;Go&lt;/a&gt;. Again, I rewrote
the optimization, using an open-source simulated annealing implementation
around the recoded objective function. This time, execution was even faster,
reaching &lt;em&gt;0.6 seconds&lt;/em&gt;. This was now performant enough to enable the
interactivity we had been hoping for, and Go&amp;rsquo;s suitability for microservices
was another strong enabler of this vision.&lt;/p&gt;
&lt;p&gt;It should be noted that neither Julia nor Go involved a massive rewrite of
the original Python objective function. Both languages allow for a procedural
style and syntax that is not very far from Python&amp;rsquo;s, so the translations were
reasonably forward, and took about half a day in each language.&lt;/p&gt;
&lt;h2 id=&#34;its-not-just-about-saving-time&#34; &gt;It&amp;rsquo;s not just about saving time
&lt;span&gt;
    &lt;a href=&#34;#its-not-just-about-saving-time&#34;&gt;
        &lt;svg viewBox=&#34;0 0 28 23&#34; height=&#34;100%&#34; width=&#34;19&#34; xmlns=&#34;http://www.w3.org/2000/svg&#34;&gt;&lt;path d=&#34;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&#34; fill=&#34;none&#34; stroke-linecap=&#34;round&#34; stroke-miterlimit=&#34;10&#34; stroke-width=&#34;2&#34;/&gt;&lt;path d=&#34;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&#34; fill=&#34;none&#34; stroke-linecap=&#34;round&#34; stroke-miterlimit=&#34;10&#34; stroke-width=&#34;2&#34;/&gt;&lt;/svg&gt;
    &lt;/a&gt;
&lt;/span&gt;
&lt;/h2&gt;&lt;p&gt;The point that excited me was not the speed per se (since we routinely
tolerate code that takes a long time to run, and adapt our workflows
accordingly). It was the &lt;strong&gt;new set of possibilities&lt;/strong&gt;, either through the
quick calculation of a lot more parameters or scenarios, or the ability
to do calculations fast enough for users to explore the problem space
in an interactive way, which is not possible when it takes 12 minutes
or longer to recalculate.&lt;/p&gt;
&lt;p&gt;In this blog site, then, I&amp;rsquo;d like to share my continuing journey around
fast data science, and using different languages, architectures, and
algorithms to enable new explorations in data science.&lt;/p&gt;
</description>
    </item>
    
  </channel>
</rss>
