Andrew Cooke | Contents | RSS | Twitter | Previous


Welcome to my blog, which was once a mailing list of the same name and is still generated by mail. Please reply via the "comment" links.

Always interested in offers/projects/new ideas. Eclectic experience in fields like: numerical computing; Python web; Java enterprise; functional languages; GPGPU; SQL databases; etc. Based in Santiago, Chile; telecommute worldwide. CV; email.

© 2006-2015 Andrew Cooke (site) / post authors (content).

Efficient, Simple, Directed Maximisation of Noisy Function

From: andrew cooke <andrew@...>

Date: Fri, 14 Dec 2018 18:04:10 -0300

Maybe this is already known - I guess it must be - but I just dreamt
it up myself.  I need to find the max (could be min, obvs) of a noise
function in 1D.

Since it's noisy I can't assume it's smooth, hope it has a global
minimum, and bisect.  I need something more robust.

At the same time, I don't want to be doing repeated evaluations of the
function where they're not needed, so any iterative deepening of a
search should re-use old values when possible.

So here's the solution:

  * Evaluate the function at 5 equally spaced points across the range
    (including the two extremes).

  * Throw away two end points.

  * Expand the remaining 3 points back to 5 by inserting new points at
    the mid-points of the existing points.

  * Repeat until you're happy.

The trick is to know which end points to discard.  It could be one
either end, or two from one end.

What I do is calculate the average of the x values at the points,
weighted by the function values there.  Then I compare this to the
unweighted average.  If it's higher, then the max is towards the high
end, so discard a low point.  Or vice-versa.  And repeat for a second

Here's an example.  The lines are (x, f(x)) pairs:

[(0.0, 0), (0.25, 5), (0.5, 10), (0.75, 1), (1.0, 1)]
[(0.25, 5), (0.375, 12), (0.5, 10), (0.625, 2), (0.75, 1)]
[(0.25, 5), (0.3125, 11), (0.375, 12), (0.4375, 10), (0.5, 10)]
[(0.3125, 11), (0.34375, 12), (0.375, 12), (0.40625, 10), (0.4375, 10)]
[(0.3125, 11), (0.328125, 11), (0.34375, 12), (0.359375, 13), (0.375, 12)]

On the first step, both ends were discarded.  On the second, two from
the "high" side, etc.  The maximum is 13 at 0.359375, roughly.

And here's the code:

def expand_max(lo, hi, n, f):
    data = [(x, f(x)) for x in (lo + i * (hi - lo) / 4 for i in range(5))]
    for _ in range(n):
        while len(data) > 3:
            w = sum(x*fx for (i, (x, fx)) in enumerate(data)) / sum(fx for (x, fx) in data)
            m = sum(x for (x, fx) in data) / len(data)
            if w > m:
                del data[0]
                del data[-1]
        x = (data[0][0] + data[1][0]) / 2
        data.insert(1, (x, f(x)))
        x = (data[-2][0] + data[-1][0]) / 2
        data.insert(-1, (x, f(x)))
    x_max, fx_max = None, None
    for (x, fx) in data:
        if x_max is None or fx > fx_max:
            x_max, fx_max = x, fx
    return x_max, fx_max


Permalink | Comment on this post

Previous Entries

For comments, see relevant pages (permalinks).

Bash Completion in Python

From: andrew cooke <andrew@...>

Date: Fri, 7 Dec 2018 08:02:11 -0300



[Computing] Configuring Github Jekyll Locally

From: andrew cooke <andrew@...>

Date: Sun, 25 Nov 2018 15:02:59 -0300

If you have docs that already exist, and that github displays on
Github Pages, then you may want to run jekyll locally - just to save on
round-tripping time or when github (as today) starts thoring errors
for no reason.

The instructions at
are pretty confusing if you already have things working on github.

What you need to do is:

* Install requirements as described (may need to run as root)

* In your local repo, at the root of the jekyll pages (for me, the
  docs directory), create the Gemfile described in step 2 and then
  install jekyll.

* Run jekyll in that same directory (step 4)

In other words, SKIP steps 1 and 3 and do everything in the docs

At least, that seemed to work for me.



[Maths, Link] The Napkin Project

From: andrew cooke <andrew@...>

Date: Tue, 20 Nov 2018 08:10:21 -0300

Introductory higher math.



[Bike] Servicing Budget (Spring) Forks

From: andrew cooke <andrew@...>

Date: Tue, 6 Nov 2018 11:49:06 -0300

Lower priced mountain biks often come with forks that contain a coil
spring (rather than an "air spring").  These tend to not get a lot of
love on the intenet.  That's partly justified - an air fork is much
more adjustable and has better damping.  But the spring forks do have
some advantages too.  Most of all, they're very low maintenance - most
people don't touch them once they've bought them.

Despite that, a little care can help keep your fork working well and
extend its life.  I just serviced mine and I thought I'd make a few
notes here ot help others.

First, I am not 100% sure what my fork is.  I removed the stickers
years ago.  I think it may be a Suntour XCM (26").  Whatever, the
general principles below should apply to pretty much and budget fork.

There are two things you can do.  The simplest (and most important) is
to remove the lowers.  More complicated is to open up the "insides"

Removing Lowers

First, remove the two bolts holding the front brake (I'm assuming
disc) so that it's no longer connected to the fork.  Also remove the
clip or zip tie or tape that holds the hose to the fork.  Then you can
ignore the brake (until the end, when we need to put it back on).

(Don't press the brake lever with the caliper loose - you can push the
hydraulic pistons out).

Turn the bike upside down, so it's sitting on the bars (or put it in a
stand if you have one I guess) and remove the wheel.  Have a look at
the bottoms of the forks.  On mine each has a 10mm nut.  Remove the
nuts and see if the you can slide the lowers off.  Don't use violence
- just pull them up with your hands while keeping the bike on the
floor with your foot.

Possibly they won't come off.  This is because the rods inside the
fork tend to stick in the ends of the lowers.  We can loosen them by
pushing the threads that the nuts were fastened on back "into" the

To do this, take a piece of wood, lay it on top of the threaded rod,
and strike with a hammer.  You may need a few attempts (change the
position of the wood since the rods makes a hole!) before the threaded
rods moves noticeably.  Once both sides are loose, you should be able
to pull the lowers off, no problem.

With the lowers off, clean the exposed stanchions and the inside of
the lowers (eg with a stick and cloth - if the cloth gets stuck
inside, blow it out from the other end).

The stanchions are steel, so can rust.  This is why it's worth
servicing them - we want them to stay smooth and clean.  So rub some
grease on them (I use random car grease - nothing fancy).

To reassemble, first put some more grease on the insides of the seals.
Then slide the lowers back on the stanchions.  Push them down and the
rods will re-appear out of the ends.  Replace and tighten the nuts
(fairly tight - you don't want these coming undone...).

Finally, replace the wheel and re-attach the brakes (once the caliper
is in place, apply the brakes and then tighten the bolts - that will
help tighten the bolts with the calipers in the right position to
avoid rubbing).

Looking Inside

If you want to look "inside" the fork, first remove the lowers (as

Next, use an appropriate tool from Suntour to unscrew the two caps on
the "top" of the fork (one on each side).  This is easier to do with
the bike lying on its side (or upright in a stand).

I'd really enourage buying the right tool.  Mine is just a plastic
wrench (looks like a big bottle opener or measuring spoon).  You can
get the caps off without it, but getting the spring side back on is
tricky (because the spring is compressed) and without the tool you're
more likely to cross-thread the cap.

If you have a lockout you may need to move the lockout knob before
removing the cap.  Mine just levers off (carefully insert a flat
screwdriver underneath and lift).

It's interesting to see what's inside, but there's not much to do
except clean and grease.  I removed an elastomer damper from "inside"
my spring so that the forks had a little more travel, but I'm not sure
I noticed much difference.  On the other side, my fork has a damper,
but it's a sealed unit with nothing to adjust.

(BTW I couldn't remove the "foot" on the spring side because the
bottom-out damper held it in place.)

Assembly is the reverse process.  Be careful replacing the cap on the
spring side as it's easy to cross-thread.  My caps are plastic so I
didn't tighten them crazy-tight.

I hope that helps.  With a little care you can keep these babies
rust-free and they'll last forever.



[Crypto] CIA Internet Comms Failure

From: andrew cooke <andrew@...>

Date: Sat, 3 Nov 2018 17:37:18 -0300

It's difficult to tell exactly what happened, but my guess from
reading between the lines is that the CIA had a bunch of fake sites
that were used as endpoints for communication.  Somehow the Iranians
detected a pattern in the way these sites were generated (eg matching
comments in the HTML source) that let them identify the sites and, via
traffic monitoring, work out who was using them.



[Python] Cute Rate Limiting API

From: andrew cooke <andrew@...>

Date: Thu, 25 Oct 2018 21:13:23 -0300

It's just a decorator -



[Causality] Judea Pearl Lecture

From: andrew cooke <andrew@...>

Date: Fri, 19 Oct 2018 12:00:01 -0300

Got confused by his book years ago, but this lecture is very good.



[Security, Computing] Chinese Hardware Hack Of Supermicro Boards

From: andrew cooke <andrew@...>

Date: Thu, 4 Oct 2018 14:36:32 -0300

Damn.  Even I have a SuperMicro board...



SQLAlchemy Joined Table Inheritance and Delete Cascade

From: andrew cooke <andrew@...>

Date: Fri, 28 Sep 2018 09:10:21 -0300

A self-contained test that should be self-explanatory

Trying to make Choochoo robust to deleted data.  It's complicated.



[Translation] The Club

From: andrew cooke <andrew@...>

Date: Sun, 23 Sep 2018 11:44:17 -0300

[I've translated this because it rings so completely true.  This is
not my profession, so the following may contain errors.  Andrew]

Daniel Matamala

Some years ago the economist Rodrigo Wagner was looking for work in
Chile, returning with a Harvard PhD tucked his arm.  The head hunter's
forst question: Which school did you go to?  Second: What do your
parents do?  Third: What do you siblings do?  "And to finish off they
asked me how many children I had, with a tone that implied I might
hold some religious belief," Wagner recalled. "And this wasn't
unusual: friends returning from MIT have had similar questions."

I remembered this anecdote while reading one of the founders of
Cornershop, Daniel Undurraga.  "It's a monopoly, working in
collusion," he said last year.  On Friday in La Segunda, he explained
that "they all know each other, they take their vacations at the same
resort, and the collusion, implicit or explicit, comes naturally.
This makes people more complacent and less innovative.  There should be
life without parole for collusion because there's no other to stop it
once and for all."

This agrees with the diagnosis of another entrepreneur, Nathan Lustig,
an American living in Chile: "Industry is highly concentrated in a few
hundred very rich families that go to the same schools and
universities.  Everyone in an elite with one or two degrees of
separation.  To compete with a friend of the family, a friend of your
friend, or a member of your church, is frowned upon, and most don't do

It goes without saying that Wagner, Undurraga and Lustig aren't
emissaries from Pyongyang or La Habana, on a campaign to install
Marxism in Chile.  They are supporters of the free market that want to
free the virtues of competition: wealth, innovation, and social

This is why the point to an obstacle to that competition: the
homogeneity of the economic elite.

Many refuse to see a problem.  Citing a figure from the OCDE Jose
Pinera celebrates the "marvelous legacy of our Liberal Revolution
... Chile has the most powerful 'social elevator' in the OCDE and
maybe the world."  For Luis Larrain the same figure "shows the lie in
what the left and much of Chilean media claim.  The opportunities to
advance in our country are much larger than in many of the countries
held up as models."

What does the famous figure really say?  That in Chile 23% of the
children from families in the poorest quartile are now in the top
income quartile - the highest proportion amongst the 15 countries

In other words, 1 in 4 of the children with least resources end up
earning over $600.000 a month (approx $900 USD) (and, therefore, the
other 3 earn less).

This is good news, and a big advance for anyone raised in poverty, but
it has nothing to do with the diversity of the elite, a club that you
obviously can't enter with just $600.000 pesos a month.

That club stays closed.  Chicago professor Seth Zimmerman shwed that
over half (53%) of the highest directorships in Chile are in the hands
of alumni from nine public (ie private) schools in Santiago: 0.5% of
Chilean students.

They form 19% of those admitted to the most competitive university
courses.  But of course, afterwards, we have head-hunters asking after
your schooling.

"Chile may be stagnating because of its oligarchy", the influential
academic James Robinson warned a short while ago.  There is a
relationship between the homogeneity of its elite and the economic
stagnation.  Already, in 1935, Pareto warned of the necessity of a
"circulation of elites" via meritocracy.  Today Brezis and Temin warn
that "a strong inter-connection between elites means that all sectors
of the economy are governed by a monolithic group."  And that is a
crucial disadvantage in times of transformation.

Where is the talent that will lead Chile through the radical change
that is coming?  Will we continue to search for it in a micro-world of
inter-connected families?  Or open the doors of merit to the other
99.5% of Chile?

Quoting Undurraga again: "The three most important engineers in
Cornershop are from Curico, Rio Bueno and La Calera."

It's not just a question of justice.  It is necessary for efficiency,
and survival.


[Computing] Super Potato Bruh

From: andrew cooke <andrew@...>

Date: Wed, 19 Sep 2018 19:48:49 -0300

This is written in Python!