In American terms I call this the 7-11/Safeway/Costco model. If you want $5 of groceries you go to a nearby small store and don't mind a high markup; if you want $500 of groceries then you drive 20 miles to a giant store with low markup. So the idea is that the variability of grocery store sizes is caused by the variability of customers purchase amounts. Here's my math model.

Take a N-by-N square grid (think of each node v representing a group of households); maybe N = 32 will be OK but "the larger N the better". Fix a function f(1), f(2), .. f(500) [in fact use a smaller number of values, say 16 instead of 500, but again the more the better]. From each node v, and for each i between 1 and 500, there are (proportional to) f(i) households at vertex v who buy exactly $i of groceries. So the total amount of groceries bought by a node is the sum \sum_i (i \times f(i)) and it's convenient to normalize f( ) to make this become 1 unit of money. The $i represents wholesale price.

At some (but not all) nodes there is a grocery store, and each grocery store has a markup, which is a real number between 0 and 1. (So 0.2 represents a 20% markup). Imagine the number of stores as say 1/10 or 1/30 of the number of nodes.

Consider someone at node v who wants to buy $i worth of groceries. If they go a particular store, their "extra cost" (above wholesale) is (a \times distance-to-store) + (i \times markup-at-store) where "a" is a fixed parameter measuring travel cost. So the customer chooses the store which minimizes this "extra cost".

Intuitively, from the viewpoint of a store we have: (if markup is relatively high): only customers living nearby and spending small $ amounts (if markup is relatively low): all nearby customers, and more distant customers spending large $ amounts.

For any given "configuration" of locations of stores; markup at each store each store gets some total dollar amount "s" of sales. The total dollar amount of sales for all stores combined is fixed at N^2 units.

This is a "static" picture; we now want to make a "dynamic" version where the configuration will change with time. Fix a function c(s) representing the break-even markup for a store. For instance c(s) = s^{-1/2}. So a store with markup "m" and sales "s" makes a profit s \times (m - c(s)) which if negative represents a loss.

From time to time, a store will change its markup, by calculating its profit for each possible markup and choosing the markup which maximizes profit. Implement this idea in our simulation by, at each step, choosing a store at random to change markup.

We also want rules for stores closing or opening. Details not important, but for instance

- after changing markup as above, if store is making a loss, we close the store with probability proportional to loss.
- every k steps we choose a node at random and open a store there if the optimal markup makes a profit.

That's the idea of the model. In writing code, the issue is maintaining a data structure. Basically, for each node we need to track: closest store; next closest store with lower markup; next closest store with lower markup;..., because these are the only possible stores for a customer at that node.

Couldn't do this in Fortran in an afternoon!

- Grid size. City grid size. Default 20.
- Purchases.
Distribution of purchase amounts at each node. A list of frequencies.
"5 0 2" denotes 5 purchases at $1, no purchases at $2, and 2 purchases at
$3. Remember to key ENTER after editing
this field.
- Seed. The random number generator (RNG) seed for the simulation. Default 0.
- Travel. Travel cost coefficient. Default 0.1.
- Break-even. Break-even markup coefficent. Default 1.0.
- Opening rate. Weekly probability of opening a new store. Default 0.5.
- Closing rate. Weekly probability of closing a loss-making store. Default 0.5.
- Markup min.
- Markup max.
- Markup step. The range of discrete values of store markup over which store profit is optimised. Default is from 0.0 to 1.0 in steps of 0.1.
- Logging. Tick here for voluminous event logging to the Java console. Default Off.

Click on the Start button to start/resume the simulation running. Click on Stop to pause. Click on Step to advance simulation by a single week. Click on the New Model button to create a new simulation with the given size, purchase distribution, and RNG seed.

As the simulation runs the weekly profit at each store is displayed as a blob on the city grid, with area proportional to profit. Stores with zero sales, giving rise to a singularity in the break-even markup function, are displayed as small white dots.