Simulating a worldwide economy

An important reason work on Particracy Classic or its handful of reboots I have undertaken over the past decade has always stalled, was that my vision of the game requires simulating a worldwide economy, and that is just really hard. Not just a player-controlled economy you see in games like Civilization or Stellaris, but an actual private sector with supply, demand, exports and imports, and government taxes, investment and regulation on top of that. Sounds easy right? One person I was talking to a few years ago referred to this particular challenge as the problem that brought down the Soviet Union, which to be honest did daunt me a little. This time around however, I’ve gained a few insights and developed techniques that I’m confident will enable me to build a decent economic model to act as a foundation for the simulation aspects of the game.

It’s the economy, stupid!William Jefferson Clinton

In this blog post, I won’t explain that model just yet, since I’m still designing it, but I’ll elaborate on the meta-model, the system the economic simulation builds upon. My sincere apologies for this being another technical post, but it’s a subject that’s dear to me, and which could be interesting for those who wonder what it’s like to build this madly complex game.

When I started experimenting with economic models for Particracy last spring, I realized that I’d need a system which would afford me a very large degree of flexibility. I didn’t want to define all sorts of variables and hard-code their behavior, only to have to scrap and redesign it many times after. I also wanted to be able to visualize the relationships between the moving parts of the simulation (supply, demand, prices, inflation, you name it) and to quickly tune the nature of those relationships.

At some point I realized I had encountered and solved these kinds of requirements before, and I thought of my favorite architectural software design pattern: the Data Flow Graph. In a typical computer program, you write code for functions or objects that call one another, all the way down until your solution bubbles back up to the top. In a data flow graph architecture, you don’t hard-code the way your functions call one another, instead you define these functions as isolated “black-box” elements with well-defined inputs and outputs, and you connect those together in a conceptual network, where data flows from one side to the other.

This network is referred to as a graph, a mathematical concept describing a network of things (called nodes), connected to one another in a particular way (through edges). The graphs used in data flow are directed graphs, where the edges have a direction, usually represented with an arrow head.

A picture can say more than a thousand words, so I’ve borrowed a picture from Wikipedia. Imagine your task is describing the data flow graph of a very simple program: one that calculates (x + y) * (x - y).
Simple data flow graph

This image shows that the program has two inputs, X and Y, and one output named Z. The graph of the program has three nodes for three arithmetic operators, each having two inputs and one output. What’s interesting about the data flow graph is that the programmer doesn’t have to specify what order the operations have to be executed in. Data just flows from input to the output, and the program can figure out on its own the order in which things have to happen. Adding one edge in a strategic place can alter said execution order completely, and the programmer won’t even know or care. All the program has to guarantee is that data flow dependencies are respected (you can’t calculate something if you don’t know the inputs of that calculation), and that there aren’t any cycles in the graph – places where the flow of the graph paradoxically depends on itself.

I’m personally very fond of this architectural pattern, because of its applicability in various domains (simulations, compilers, content generation, graphics engines, user interfaces …), its conceptual simplicity, its innately visual aspect, and the way it can be automatically run in parallel. I’m not alone in recognizing the relevance of this pattern, as it’s widely used in the graphics industry for defining shaders and procedural texture generators. In any practical application of this architecture, the nodes will represent more complex operations than just arithmetic. In a graphics system, they could be filter processes, fractal noise sources, texture assets, blending operations or complicated mathematical functions.

A more complex example

In my application of the data flow graph, which is a simulation of macro-economics, I’m relying on the following assumptions:

  • Nodes have a set of input and output ports, and no additional ways to pass data (no global variables).
  • Nodes have no internal memory, so the only way to preserve state is to express it as an output.
  • Data passed over the edges to the nodes is immutable, meaning it cannot be changed. You don’t overwrite a number in an array, for instance, you pass the modified value as an output.
  • Data is either a number, an array or a bundle.
  • Numbers are simple double-precision floating-point values. No integers required.
  • Arrays are unordered lists of numbers. They get created whenever an input has more than one incoming edge, and are really only used for situations where a sum of multiple data flows is required.
  • Bundles are structured data, mapping textual keys to numbers. This allows the combining of different data flows into a single flow, thus reducing conceptual (and visual) clutter in the graph. An example of such a bundle would be {steel: 120, coal: 80}. I got the idea off the strategy game Factorio, where a wire carriers signals for many different kinds of resources.
  • Edges connect node output ports with node input ports, and there are two kinds of edges.
  • Immediate edges link data that flows from one port to another as soon as it becomes available. All immediate edges together have to constitute an acyclic graph, because otherwise calculation would not be possible.
  • Delayed edges represent a link that is only activated when the next simulation frame starts. These are used for representing the final outputs of a simulation frame, for solving cyclic dependencies where required, and for providing feedback mechanisms. For instance, the node modeling pollution effects would link back to itself using a delayed edge, since the pollution doesn’t just reset overnight, it stays until it is slowly cleaned up. That implies yesterday’s pollution is carried over to today.
  • Nodes represent a process or actor that participates in the game’s economy. Examples of these would be: income tax policy, the agriculture sector, household consumption, foreign imports, etc.
  • Each territory in a game world is first simulated independently, so all the processes operate with the values inside that territory (workforce, capital, socio-economic metrics, …).
  • Trade between different territories, and ultimately different nations, is conducted on top of that, probably with a completely different instance of a data flow graph.
  • Visually in my debugging environment, nodes are represented as boxes with their inputs on the left and their outputs on the right. Immediate edges are drawn using a full line, and delayed edges become dotted lines. Each edge is also given a box where my development environment shows information on the values the edge has been given over multiple simulation frames. Different types of data (money, people, percentages, quantities, …) are represented in different colors.

Economy data flow graph example

An example of a trivial, generic operation which is used all over in the model, is the Bundle node, which combines multiple flows of data into one. As you can see, the data flow edge carrying the bundle data is represented with a thicker line, and the edge’s value information box just shows how many entries there are in the bundle.
Economy data flow graph example

An example of a node specific to the simulation, is the one that controls the labor market. This node receives the population number as input, along with the state of the workforce (how many people work in which industrial sector), and the demands of these sectors in terms of hiring or firing, from the previous simulation frame. The output then specifies how many people work in each industrial sector in the new simulation frame, which in turn is used to control production for each sector. The fat dotted line clearly highlights how the workforce data feeds back into the node for the next frame. Obviously this model is incomplete, since it doesn’t have a way to represent the inactive portion of the population (children, the elderly, …), so there’s room for improvement.
Economy data flow graph example


I’m going to have to strike a subtle balance between complexity and simplicity when building up the economic model in order to make this manageable. What I won’t do is model ten thousand individual corporation in the game, because it ultimately isn’t a business simulator. What I do want to see is uranium embargoes and oil deals, tropical islands living off tourism and fertile areas which feed entire nations. In my view, this system is a solid start towards that objective. At some point I’ll probably do a follow-up to this post, where I can go into more detail on the actual economic model, rather than the system that powers it.

 

Wouter Lievens

I'm the designer and developer of Particracy, an online political strategy game. I came up with the first incarnation of the game, now called Particracy Classic, in 2005. After several attempted sequel or remake projects over the years, I've finally committed to building the ultimate version of Particracy, and I'm going at it full time to make it happen.

 

3 thoughts on “Simulating a worldwide economy

  1. I’m an economist IRL, and I’d be happy to help you construct a model economy. You’d be surprised how simple that could be.

    And don’t worry, the causes of the Soviet Union’s dissolution were political, not economic.

    1. Hi there, this looks very promising.

      How will you model productivity, as in, output produced per laborer? Will you model investments, allowing sectors that make profits to invest that profit in their capital stocks, increasing productivity? Will you have capital goods, like machinery, that are “inputs” for investment, and which you can, i..e., subsidise to boost investments?

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.