Recent submissions

Comment · 2 hours ago
> Running the suite in CI on every build would have caught a lot of this

yeah, provided:

  1. test cases are being designed to cover functionality
  2. test cases are implemented correctly - i.e. they actually fail if the implementation is defective
  3. the tests aren't all commented out
  4. the test suite fails if a test fails
  5. CI actually detects test suite failure
  6. failing tests block changes from being merged (apart from initial triage to stabilise the suite)

Presumably a few of these things weren't being done -- I'd bet 1 & 2 were skipped or implemented so poorly that they were worse than having no tests at all -- checking nothing but giving a false illusion that some kind of testing had happened.

Five years ago, outsourcing your software development (including QA) to the lowest bidder might have gotten you results like this -- if you didn't explicitly require automated tests as a deliverable, you wouldn't get any, or if you got some they'd be vacuous and not test anything.

Comment · 2 hours ago
> how this was allowed to be tested

I can see it happening if they genuinely had no idea of how defective / non-existent their internal QA & testing processes were.

Comment · 1 day ago
If the US were to follow this excellent idea to raise revenue, it could completely solve the federal budget deficit.

A modest download tax of USD $2.07 per GB suffices.

Estimate:

  - 134 million households
  - approx 80% of households subscribe to home broadband
  - approx 750 GB download per month per household
  - $2 trillion annual deficit
  - assumes no change in household behaviour in response to the new tax
Comment · 3 days ago
Comment · 4 days ago
It's possible for both a new technology to be hugely beneficial in the long run & for early investors to lose a lot of money funding it (if they over-invested / over-paid).
Comment · 4 days ago
Yep! Or for a slightly generalised example, if we pick our sublinear function of n to be n^(1-epsilon) for some small epsilon > 0

then 2^(n^(1-epsilon)) belongs to 2^o(n)

Suppose p(n) is some polyonomial in n, our polynomial reduction. Let's make it a monomial for simplicity, p(n) = n^a

Does 2^(p(n)^(1-epsilon)) necessary belong to 2^o(n)?

No, that only holds if (n^a)^(1-epsilon) = n^(a (1-epsilon) ) < n^1 . So, it fails for p(n) = n^a for any a such that a >= 1/(1-epsilon)

Comment · 5 days ago
A historical episode that may arguably be related -- regarding stock market euphoria & overbuilding capacity -- was the dot-com era Telecom bubble & crash [1].

Even if something is a reasonable infrastructure project with a sound long term business plan, investors can still lose money if they pay too much for it. For the Telco bubble & crash, there were a few of these Telco companies engaging in financial shenanigans / securities fraud to juice their quarterly financials by leasing capacity to artificially inflate their operating revenue etc. E.g. we booked $100m of revenue by leasing X units of our capacity to $competitor! Sure, we're still extremely cashflow negative, but look at our operating revenue grow! Fine print: we also incurred a symmetric $100m expense to lease X units of capacity back from the same $competitor, but for some reason we didn't classify that as an operating expense, we've thrown it into a different accounting bucket.

That said, overbuilding fiber optic capacity by laying undersea cables is likely different to overbuilding GPU datacenter capacity in that most of the cost of laying a cable is the physical cost to lay the cable -- given you're already laying an undersea cable, the incremental cost to add a bit more capacity to it (more optical fibers) is negligible -- at least before you've sunk the cable! Whereas for a data center full of GPUs, maybe 50%-60% of the total cost is the GPUs, so it isn't cheap to massively overbuild capacity.

[1] https://en.wikipedia.org/wiki/Telecoms_crash

Comment · 8 days ago
Cool, the interactive visualisation is a great way to explain it.

Maybe a similar-ish idea could be done in a continuous 2d space, without a grid, using 2D computational geometry operations (e.g. GEOS's [1] buffer operation to grow shapes by a given radius & so on).

Each component is a point-set -- a subset of points in the 2d space we're working in.

  1. sample a bunch of seed points from some distribution. these define initial connected components
  2a. grow each component by radius r. union any components that touch.
  2b. shrink each component by radius r + delta. delete components that contain no points
  3. delete any components that are 'too small': shrink each component by r_min, delete any components that now contain no points, then grow each surviving component by r_min again
  4. link the surviving connected components somehow:
  4a. identify pairs of components that are adjacent (e.g. compute voronoi 'triangulation' using components as seeds instead of points, if two resulting triangles border then their components are neighbours)
  4b. propose candidate corridors linking the nearest points between each pair of adjacent components
  4c. find a minimal/interesting spanning tree on component-corridoor graph using corridor lengths as edge weights
  4d. carve selected corridors by growing each coridoor line by some radius
  4e. everything should be some big connected component
  5. sanity check that we got something playable (maybe based on area). if it's too small/uninteresting, reject & try again from step 1

I'm not sure of an efficient/reasonable way to do step 4a in the plane - it'd be simple & efficient to do this on a graph (Voronoi-triangulating a graph has similar computational cost to finding all shortest paths from some source - it's like a multi-source BFS with bookkeeping to recover a shortest path to the closest source, with a little extra bookkeeping & logic).

Nethack's cellular automata gnomish mine algorithm on a small grid is of course going to be massively faster than stuffing about with masses of GEOS Buffer & Union calls, but it's fun to think through how much of this extends.

[1] https://libgeos.org/

Comment · 14 days ago
Paul, cheers for your thoughtful reply -- all the best with PressAudit
Comment · 14 days ago
I was curious about the issue the author called out with the baseline knapsack algorithm -- that it was running out of memory.

It looks like pytorch's various knapsack implementations (including the one contributed by the author) are here:

https://github.com/pytorch/pytorch/blob/31ba9a56657bc887c957...

appears to be used e.g. here

https://github.com/pytorch/pytorch/blob/31ba9a56657bc887c957...

One thing that jumps out at me while staring at the baseline dp_knapsack code is that it isn't very clear what the units used to measure memory are meant to be. The dp_knapsack code assumes that memory & max_memory (aka the memory budget) are floats. dp_knapsack internally multiplies these floating-point memory values by 10,000 & then rounds them to integers to quantise the memory values -- the quantised max_memory value defines the size of one dimension of the dynamic programming table. the other dimension is sized by the item count.

From reading patches of partitioners.py, it seems like the memory budget is meant to be a floating point number between 0.0 & 1.0, and presumably the memory of each item is normalised relative to that memory budget?

If so, & dp_knapsack is called with a max_memory of 1.0, then the a 2d array for n items is allocated and m=10,000 quantised memory values is allocated as shape (n+1, m+1). So for 100 items that'd be an array of shape (101, 10001) - it's filled with float32s, so 4 bytes per element, so the size required for the table would be ... about 4MB.

So it's not obvious why that would be running out of memory.

Another possible explanation of why the baseline dp knapsack could be using a bunch of memory -- speculation -- is that some code could be calling dp_knapsack with a different unit convention than what dp_knapsack expects --- suppose a caller passes in memory & max_memory values that are measured in floating-point GB. If the max_memory was passed in as 1024.0 then, for 100 items, the dp_knapsack code would allocate a float32 array of shape (101, 10240001) and this would require about 4GB.

Given the units of these inputs aren't documented (& certainly not enforced by the type system) & there aren't runtime range checks on the value of max_memory there's a lot of room for something like this to be happening.

Perhaps dp_knapsack could be reimplemented where it is responsible for rescaling input memory values relative to max_memory, where the rescaling always forces max_memory to be 1 before the memory values are quantised. Then there wouldn't be a way for the caller to get the undocumented calling convention wrong.

Comment · 15 days ago
Here's a few related ideas:

1) rejection sampling - this is the name to the general technique used in the first example, to estimate pi by sampling from a uniform distribution over a unit square (easy) and then rejecting the samples that fall outside of the distribution you're actually interested in (unit disk).

Another simple example of rejection sampling is if you want to randomly pick between 5 ordered options and only have a d6. Roll the d6. If you roll a 6, reject the roll & re-roll. If you roll 1-5, that's your choice.

2) the Metropolis-Hastings algorithm -- this is a Markov chain Monte Carlo algorithm. It can be useful in some applications to sample from a distribution that is difficult to sample from.

Suppose you have some system described by a state vector x & you know that the probability of the system being in state x, p(x), is proportional to q(x), where q is some function you can compute. If you could integrate q over x, to give Z := integral_{x in X} q(x) dx then you'd have p(x) = Z^-1 q(x)

For a concrete example, x might be a state vector of a physical system -- say a bunch of molecules in a box, where you can compute the energy of any given state u(x) and know the probability of x, p(x), is proportional to exp(-u(x)).

Metropolis-Hastings is neat as it gives you a way to sample from p even if you cannot compute Z or sample from q --- you just need to have some way to sample a proposed a new candidate state x' from x (this proposal distribution doesn't need to have any relationship to the distributions p & q you're actually interested in). Can often think of the proposed candidate state x' as some kind of local mutation of x. Provided you can compute q(x') / q(x), you can use that ratio as a probability of accepting the move to replace x with candidate x'.

By the algorithm depending on the ratio of probabilities of two different states p(x') / p(x) = q(x') / q(x), it lets you sample from p even if you can't compute Z or have any direct way to sample from p or q. *

Metropolis-Hastings & Markov Chain Monte Carlo methods are definitely in the territory of clever 'what to do if you don't know what to do' methods --- if there's some other more direct & practical way of computing the thing you're trying to compute, use that instead! But if there's not, & you have some gnarly problem, maybe MCMC might be the best option available.

* caveat caveat caveat: provided you let the sampler run long enough for it to 'burn in', & perhaps restart it a few times from different initial states x_0 to reduce the chance of it getting trapped in some unrepresentative local optima

Comment · 15 days ago
Comment · 16 days ago
be the change you want to see in the world
Comment · 19 days ago
Comment · 19 days ago
When you say pointer heavy, just how heavy is that pointer?

In traditional brainfuck, a single < suffices to move The Pointer one cell to the left.

For a dialect of brainfuck where The Pointer is 3x as heavy as is traditional, you'd have to apply 3x the effort, i.e. <<<, in order to move one cell to the left.

Cursed bogocomputing idea of the day: a variant of brainfuck where The Pointer is physically simulated, with mass & momentum. < & > apply impulses. The Pointer continues to move across The Array with momentum after you apply an impulse.

Live from the official Hacker News API

A modern reader for Hacker News · SvelteKit + Skeleton