Planet Cache Valley Tech

February 08, 2023

David Owen (SE)

In-order responses for asynchronous work

Sometimes we end up executing some asynchronous function several times in a row, but we need only the results of the last call. The difficulty is that some earlier invocations may finish after the latest. I encounter this most often in Javascript, when I call an API in response to ongoing user input, like for looking up an address. While debouncing can help reduce this problem (and should be done anyway to lighten the load), it does not eliminate the problem.

A simple way to do this is to use a counter to keep track of each request, and only process a response if it's newer than any other processed so far.

Continue reading "In-order responses for asynchronous work"

by David Owen (dsowen@fugue88.ws) at February 08, 2023 02:00 PM

March 07, 2022

David Owen (SE)

March 04, 2022

David Owen (SE)

Better averages for online machine-learning

Averages are used, in some form or other, and many machine-learning algorithms. Stochastic gradient descent is a great example of an average in disguise, thin though it may be.

Picking the right kind of average can be critical. As learning algorithms explore sub-optimal choices, the resulting negative impact on backed-up state values can persist over epochs, hampering performance. Alternatively, some kinds of average don't converge, preventing the algorithm from settling into optimal outcomes.

Here, I officially release a paper on a particular kind of average that's adaptable like an exponential moving average, but has guaranteed convergence like a simple average.

Continue reading "Better averages for online machine-learning"

by David Owen (dsowen@fugue88.ws) at March 04, 2022 08:42 PM

April 13, 2021

David Owen (SE)

Action-selection and learning-rates in Q-learning

Implementing a Q-table reinforcement-learner is in many ways simple and straight-forward and also somewhat tricky. The basic concept is easy to grasp; but, as many have mentioned, reinforcement-learners almost want to work, despite whatever bugs or sub-optimal math might be in the implementation.

Here are some quick notes about the approach I've come to use, specifically about action-selection (e.g. epsilon-greedy versus UCB) and managing learning-rates. They've helped my learners converge to good strategies faster and more reliably. Hopefully they can help you, too!

Continue reading "Action-selection and learning-rates in Q-learning"

by David Owen (dsowen@fugue88.ws) at April 13, 2021 01:00 PM

December 30, 2020

David Owen (SE)

Simulating deck-shuffling

I recently worked on a small project simulating random events that were far too numerous to enumerate. In such cases, every bit of speed matters.

The project in this case was similar to determining likelihood of five-card Poker hands in seven-card draws.

Simulation of shuffling the deck and drawing cards can take a large part of the runtime if not done well, but there's a trick that makes it almost trivial.

Continue reading "Simulating deck-shuffling"

by David Owen (dsowen@fugue88.ws) at December 30, 2020 02:00 PM

June 16, 2020

David Owen (SE)

Exact random sums

Sometimes, you need a list of random numbers that sum to a known constant. There's a known algorithm to provide this list of numbers with the proper distribution, but a straight-forward implementation may give a list that doesn't sum exactly to the desired constant because of rounding error.

This article describes the basic algorithm, why the rounding error happens, and the solution.

Continue reading "Exact random sums"

by David Owen (dsowen@fugue88.ws) at June 16, 2020 01:00 PM

June 02, 2020

David Owen (SE)

Precision of random numbers

In some sense, random numbers uniformly-distributed in the range \([0, 1)\) are the easiest class of random number to generate.

Because of the internal representation of floating-point numbers, all you need to do is fill the significand with random bits, set the exponent to -1, and the sign bit to positive.

Some language run-times do this better than others.

This article shows how to check your run-time, and how to fix it.

Continue reading "Precision of random numbers"

by David Owen (dsowen@fugue88.ws) at June 02, 2020 01:00 PM

March 12, 2019

David Owen (SE)

certbot and tinydns

Let's Encrypt now supports wildcard certificates. To confirm DNS control, they support several different DNS providers and dynamic DNS protocols, but they don't yet have a plugin for tinydns by DJ Bernstein.

Luckily, the excellent designs of both certbot and tinydns make it very easy to support on your own.

Continue reading "certbot and tinydns"

by David Owen (dsowen@fugue88.ws) at March 12, 2019 01:00 PM

September 22, 2017

David Owen (SE)

von Neumann's 4-player {1/3, 1/3, -1/3, -1/3} imputation

In Theory of Games and Economic Behavior, von Neumann discusses solutions to some kinds of zero-sum four-person games. See section 37.4.2, page 317. There, he finds that one set of imputations is incomplete, and must have at least another imputation added to it. He writes that [it] seems very difficult to find a heuristic motivation for the steps which are now necessary before giving the imputation as:

\begin{equation} \vec a^{IV} = \left\{1/3, 1/3, -1/3, -1/3\right\} \end{equation}

The situation is unusual in that the first three players have formed a coalition against the fourth. So, why does the third player have the same loss as the fourth? This is the heuristic that von Neumann didn’t provide, and he concludes by saying only that [if] a common-sense interpretation of this solution… is wanted, … it seems to be some kind of compromise between a part (two members) of a possible victorious coalition and the other two players.

However, there’s an intriguing possibility.

Continue reading "von Neumann's 4-player {1/3, 1/3, -1/3, -1/3} imputation"

by David Owen (dsowen@fugue88.ws) at September 22, 2017 01:23 AM

April 11, 2017

David Owen (SE)

Exponential Moving Average (EMA) Rates, part 3

In the last post, we created an online implementation of an EMA to measure the rate of a Poisson event. However, it has the “warm-up” period seen in most EMA implementations.

This time, we’ll correct that. The technique is similar to what I wrote in The correct way to start an Exponential Moving Average (EMA).

Continue reading "Exponential Moving Average (EMA) Rates, part 3"

by David Owen (dsowen@fugue88.ws) at April 11, 2017 01:00 PM

March 28, 2017

David Owen (SE)

Exponential Moving Average (EMA) Rates, part 2

In the last post, we simulated some Poisson data and then verified it by looking at its histogram and some descriptive statistics. We also built a basic sliding-window implementation and graphed its output.

To continue on, we’ll need to build a more realistic implementation, along with a method to feed it the simulated events. With that in hand, we’ll build an EMA function specialized for Poisson events.

Continue reading "Exponential Moving Average (EMA) Rates, part 2"

by David Owen (dsowen@fugue88.ws) at March 28, 2017 01:00 PM

March 14, 2017

David Owen (SE)

Exponential Moving Average (EMA) Rates, part 1

I had been thinking about determining the average rate of occurrences over time of some observation. For example, you might like to measure how much traffic flows through a street throughout the day. Reporting the time that every single car goes by is very accurate, but not very useful. You might bin traffic into hours starting on every hour, but if there is a spike or sudden increase in the middle of an hour you might miss its significance. So, you'd like to see a graph that's smooth like an average but with more detail in time.

One approach is similar to the binning approach, but slide the hour-long window across the data by minutes. Doing this requires keeping the data around, and using each data point repeatedly. If you have a surge of one million cars in a few minutes, you need to use those million points in your calculations 60 times.

This behavior is similar to the Simple Moving Average (SMA). A SMA can easily be transformed into an Exponential Moving Average, which requires only the previous EMA and the new data point to calculate the new EMA. So, I decided to create an Exponential Moving Average Rate (EMAR).

Continue reading "Exponential Moving Average (EMA) Rates, part 1"

by David Owen (dsowen@fugue88.ws) at March 14, 2017 01:00 PM

January 31, 2017

David Owen (SE)

The correct way to start an Exponential Moving Average (EMA)

The EMA is a very handy tool. It lets us calculate an average over recent data. But, unlike a Simple Moving Average, we don't have to keep a window of samples around—we can update an EMA "online," one sample at a time.

But the perennial question is: how do you start an EMA?

First, here are a couple of wrong ways.

Continue reading "The correct way to start an Exponential Moving Average (EMA)"

by David Owen (dsowen@fugue88.ws) at January 31, 2017 02:00 PM

January 24, 2017

David Owen (SE)

Deciding once

In Fixing dispatch, we refactored some code that dispatched things from a switch-statement or cascading if-statements to dispatching by polymorphism.

This time, we'll refactor a different piece of dispatch in a completely different way, and cover another design principle.

Continue reading "Deciding once"

by David Owen (dsowen@fugue88.ws) at January 24, 2017 02:00 PM

January 03, 2017

David Owen (SE)

Fixing dispatch

A fun thing about refactoring code is that after one refactor is finished, the next candidate is easier to see.

In An abstraction gone wrong, we refactored the state variable of a simple tokenizer from an integer into an object. Now that that's done, another problem is staring at us in the face. It's in this code:

if (state == INITIAL) {
    // ...
} else if (state == IN_NUMBER) {
    // ...
} else if (state == IN_STRING) {
    // ...
} else if (state == AFTER_STRING) {
    // ...
} else if (state == ESCAPING) {
    // ...
}
Continue reading "Fixing dispatch"

by David Owen (dsowen@fugue88.ws) at January 03, 2017 02:00 PM

December 27, 2016

David Owen (SE)

An abstraction gone wrong

A given abstraction can be helpful in one situation and harmful in another. Often, we use abstractions out of habit without thinking critically about their benefit. Sometimes, an abstraction is harmful because it distances us from other features of the language, as I wrote in Abstractions.

Here, I give an example of such an abstraction, which happens to be very common in the domain of parsing, but which comes up in many other places. I also begin refactoring the code to use a more helpful abstraction.

Continue reading "An abstraction gone wrong"

by David Owen (dsowen@fugue88.ws) at December 27, 2016 02:00 PM

December 23, 2016

Jamis Buck

Process Roulette

Announcing a party game for developers, but with a few caveats — 3-minute read

by Jamis at December 23, 2016 07:00 AM

December 13, 2016

David Owen (SE)

Abstractions

Abstraction allows us to wrap up complication into a simpler form. We can take a set of things, with all of their nuances and details of combination, wrap it all up and call it new thing.

But, abstractions can sometimes get in our way. If they're not designed properly, they may not go together in convenient ways, or they may distance us from other useful parts of the language.

Continue reading "Abstractions"

by David Owen (dsowen@fugue88.ws) at December 13, 2016 02:00 PM

December 06, 2016

David Owen (SE)

Context-based programming is DRY

Recently, I needed to document firewall rules for a cluster of machines. The document needed to spell out rules by machine, but that meant that connections between machines were described in two places: the machine requesting the connection, and the one servicing it.

Context-based programming gave me an easy to describe a connection in a single place, but generate a document that connection in two places.

I can also use the same source file to generate the firewall rules themselves.

Continue reading "Context-based programming is DRY"

by David Owen (dsowen@fugue88.ws) at December 06, 2016 02:00 PM

November 29, 2016

David Owen (SE)

Context-based programming

There's a style of programming that I stumbled across a while ago. I don't remember hearing about it anywhere else before, so I thought I'd write about it here.

I call it "context-based programming." Code is expressed using terms that are defined by a context, and the user can control the context and how the terms are defined.

Here's a simple example:

Continue reading "Context-based programming"

by David Owen (dsowen@fugue88.ws) at November 29, 2016 02:00 PM

November 19, 2016

Jamis Buck

Weekly Programming Challenges -- Recap

Recapping the last 16 weeks of weekly programming challenges — 2-minute read

by Jamis at November 19, 2016 07:00 AM

November 12, 2016

Jamis Buck

Weekly Programming Challenge #16

The Midpoint Displacement Algorithm — 4-minute read

by Jamis at November 12, 2016 07:00 AM

November 05, 2016

Jamis Buck

October 29, 2016

Jamis Buck

October 22, 2016

Jamis Buck

Weekly Programming Challenge #13

Poisson Disk Sampling with Bridson's Algorithm — 4-minute read

by Jamis at October 22, 2016 06:00 AM

October 15, 2016

Jamis Buck

Weekly Programming Challenge #12

Family Trees and Pedigree Charts — 4-minute read

by Jamis at October 15, 2016 06:00 AM

October 08, 2016

Jamis Buck

October 01, 2016

Jamis Buck

September 24, 2016

Jamis Buck

August 16, 2015

David Owen (SE)

April 25, 2015

David Owen (SE)

A crazy fast bit-counting technique

Let's say that you've got a lot of numbers that represent bitmasks of some kind, and you want to count how many times each bit is on or off across the entire set.  Maybe you're analyzing game positions represented as bitboards for an AI, or trying to find certain types of weaknesses in random-number generators, like in Forge (a successor to crypto-js) or Cryptocat (at archive.org) (read the great write-up at Sophos).

So, you write some very straight-forward code to count the bits.  It grabs one bitmask.  If the lowest-order bit is set, it increments the counter for that bit position.  Then, it right-shifts the bitmask and moves to the counter for the next bit.  Repeat that for each bit in the mask, then repeat that for each bitmask:

const int N = 1000000;
unsigned long x[N]; // Assuming sizeof(unsigned long) == 8, or 64 bits.
int counts[64] = {0};

void count_simple(void) {
    for(int i = 0; i < N; i++) {
        int j = 0;
        while(x[i] != 0) {
            counts[j] += x[i] & 1;
            x[i] >>= 1;
            ++j;
        }
    }
}

You run your program, and it works correctly, but it's too slow.  I'll show you how to speed this up.  The technique, which applies to languages like Python or Javascript as well as to C, is both crazy, and crazy-fast!

Continue reading "A crazy fast bit-counting technique"

by David Owen (dsowen@fugue88.ws) at April 25, 2015 11:48 PM

September 19, 2014

David Owen (SE)

Working with wrap-around

Sometimes we need to work with numbers that wrap-around, such as angles or indexes into a circular array. There are some tricks for dealing with these cases. Continue reading "Working with wrap-around"

by David Owen (dsowen@fugue88.ws) at September 19, 2014 01:16 AM

September 15, 2014

David Owen (SE)

Bounds-checking with a circular sector

A circular sector is the part of a circle bounded by two radii and an arc connecting them. Determining whether a point lies in a sector is not quite as easy as rectangular bounds-checking. There are a few different approaches: θ-comparison, line-sides, and dot-products. Continue reading "Bounds-checking with a circular sector"

by David Owen (nospam@example.com) at September 15, 2014 10:22 PM