Skip to content

Supply chains

In the previous chapter, we ranked production units (buildings with certain production methods combinations) by their employment and construction requirements. But in the end, a country's economy cannot be solely based on oil rigs and automobile factories (unless you actually go for it). A world-dominating superpower's economy must be self-sufficient, which means some people must work in less productive production units to produce the upstream goods.

So this time, our analysis focuses on goods. We will find a set of production units, so that overall, the set produces at least a certain amount of a specific good (and maybe some inevitable byproducts) but consumes only labor and construction points, and no other goods at all. We call this set of production units a supply chain.

The supply chain can be visualized as a directed graph, where the nodes are goods and production units, and the edges are the flows of goods between them.

There are multiple implementations of a supply chain, one of which would be optimized for different objectives, such as minimizing employment or construction points. We are here today to find them, with the help of examples/supply_chain_compare.py, which solves for the minimum employment and minimum construction supply chains for every producible good, under different configurations.

The supply-chain guide explains the API and graph model. The data dictionary defines the report columns, units, formulas, and failure behavior.

View examples/supply_chain_compare.py

Methodology

To normalize the comparison, each supply chain has a weekly target base value of £100,000 of its corresponding terminal good, with target quantity calculated as 100_000 / base_price. This is fixed export demand with a zero goods-balance floor and no imports. Surplus and coproducts are possible, so equal target value does not imply equal GDP or make goods interchangeable.

The following table summarizes the three scenarios used in the comparison, with their objectives and additional restrictions. The cangshulun preset, originating from this video, bans certain oil-using production methods to represent the resource constraints. Monuments, ownership buildings and government buildings are also banned in all configurations, as they are not part of the production chain.

Configuration Objective Technology and additional restrictions
era_3_construction Minimum whole-system construction Era 3
era_5_automation Minimum whole-system employment Era 5
cangshulun Minimum whole-system employment Era 5, CANGSHULUN_BANNED_PMS, and CANGSHULUN_BUILDING_LIMITS

Note that the above constraints do not simulate every in-game law, qualification, or state-specific PM restriction. These are idealized model requirements, with no wage costs or profession availability constraints.

A failed solve produces a configuration-summary row with its requested target, status, and error text, and the script continues to the next configuration and good. Failed configurations have no detailed reports or plots. Unknown goods, duplicate good keys, and invalid base prices raise before any output is written.

The automobile supply chain

The employment and construction requirements for the automobile supply chain under different scenarios are summarized in the following table.

Configuration Status Employment (workers) Construction (points)
Era 3 construction Infeasible Unavailable Unavailable
Era 5 automation Success 125,161 25,217.7
Cangshulun Success 138,218 27,713.7

The £100,000 target corresponds to 1,000 automobiles per week. Both successful cases produce £100,000 of weekly value added, or £5.2 million annually, while using different amounts of labor and construction. In this example, whole-system and terminal-chain totals agree; that equality is not a general guarantee of the API.

Within analyses/supply_chains/era_5_automation/automobiles/, the reports explain where those requirements come from:

  • goods.csv and goods_balance.svg compare supply, consumption, imports, and net production. The terminal production floor is a separate constraint, rather than a population or export buy order.
  • processes.csv identifies the selected building/PM configurations and their levels. flows.csv records process inputs and outputs.
  • workforce.csv and workforce.svg describe employment by profession. Minimizing total employment does not necessarily minimize skilled labor.
  • constraints.csv, bottlenecks.csv, and constraints.svg expose LP diagnostics and useful binding inequalities. Marginals are local and objective-specific, and constraints can have different units.
  • alternatives.csv lists all allowed producer configurations, including inactive ones. The diagrams can prune alternatives for readability.

Weekly goods supply, consumption, imports, and net production in the era 5 automobile chain

Era 5 automation: automobile-chain goods balance, in units per week.

Binding constraints and their objective improvement per relaxed unit in the era 5 automobile chain

Era 5 automation: binding automobile-chain constraints, measured in workers saved per relaxed constraint unit.

The supply chain network graphs

supply_chain_recipe.mmd shows the allowed technology and supply_chain_realised.mmd the realized chain. network.svg weights realized edges by base-price value. Its layout distances have no economic units.

Allowed automobile technology in the era 5 automation preset:

flowchart LR
    n0(("aeroplanes"))
    n1(("automobiles ★"))
    n2(("clippers"))
    n3(("clothes"))
    n4(("coal"))
    n5(("copper"))
    n6(("dye"))
    n7(("electricity"))
    n8(("engines"))
    n9(("explosives"))
    n10(("fabric"))
    n11(("fertilizer"))
    n12(("fish"))
    n13(("fruit"))
    n14(("furniture"))
    n15(("glass"))
    n16(("grain"))
    n17(("hardwood"))
    n18(("iron"))
    n19(("lead"))
    n20(("liquor"))
    n21(("meat"))
    n22(("oil"))
    n23(("paper"))
    n24(("porcelain"))
    n25(("rubber"))
    n26(("services"))
    n27(("silk"))
    n28(("steamers"))
    n29(("steel"))
    n30(("sugar"))
    n31(("sulfur"))
    n32(("tanks"))
    n33(("tools"))
    n34(("transportation"))
    n35(("wood"))
    n36["building_automotive_industry<br/>lvl=0"]
    n37["building_automotive_industry<br/>lvl=0"]
    n38["building_automotive_industry<br/>lvl=0"]
    n39["building_automotive_industry<br/>lvl=0"]
    n40["building_automotive_industry<br/>lvl=0"]
    n41["building_automotive_industry<br/>lvl=0"]
    n42["building_automotive_industry<br/>lvl=20 | active"]
    n43["building_automotive_industry<br/>lvl=0"]
    n44["building_chemical_plant<br/>lvl=0"]
    n45["building_chemical_plant<br/>lvl=0"]
    n46["building_chemical_plant<br/>lvl=0.03524 | active"]
    n47["building_coal_mine<br/>lvl=0"]
    n48["building_coal_mine<br/>lvl=0"]
    n49["building_coal_mine<br/>lvl=0.4393 | active"]
    n50["building_copper_mine<br/>lvl=0"]
    n51["building_copper_mine<br/>lvl=0"]
    n52["building_copper_mine<br/>lvl=0.3686 | active"]
    n53["building_cossack_host<br/>lvl=0"]
    n54["building_cossack_host<br/>lvl=0"]
    n55["building_cotton_plantation<br/>lvl=0"]
    n56["building_cotton_plantation<br/>lvl=0"]
    n57["building_cotton_plantation<br/>lvl=0"]
    n58["building_dye_plantation<br/>lvl=0"]
    n59["building_explosives_factory<br/>lvl=0"]
    n60["building_explosives_factory<br/>lvl=0.1379 | active"]
    n61["building_explosives_factory<br/>lvl=0"]
    n62["building_fishing_wharf<br/>lvl=0"]
    n63["building_fishing_wharf<br/>lvl=0"]
    n64["building_fishing_wharf<br/>lvl=0"]
    n65["building_glassworks<br/>lvl=0"]
    n66["building_glassworks<br/>lvl=0"]
    n67["building_glassworks<br/>lvl=0"]
    n68["building_glassworks<br/>lvl=0"]
    n69["building_glassworks<br/>lvl=0"]
    n70["building_glassworks<br/>lvl=0"]
    n71["building_iron_mine<br/>lvl=0"]
    n72["building_iron_mine<br/>lvl=0"]
    n73["building_iron_mine<br/>lvl=1.186 | active"]
    n74["building_lead_mine<br/>lvl=0"]
    n75["building_lead_mine<br/>lvl=0"]
    n76["building_lead_mine<br/>lvl=0"]
    n77["building_livestock_ranch<br/>lvl=0"]
    n78["building_livestock_ranch<br/>lvl=0"]
    n79["building_livestock_ranch<br/>lvl=0"]
    n80["building_logging_camp<br/>lvl=0"]
    n81["building_logging_camp<br/>lvl=0"]
    n82["building_logging_camp<br/>lvl=0"]
    n83["building_logging_camp<br/>lvl=0.01241 | active"]
    n84["building_logging_camp<br/>lvl=0"]
    n85["building_logging_camp<br/>lvl=0"]
    n86["building_motor_industry<br/>lvl=2.48 | active"]
    n87["building_motor_industry<br/>lvl=0"]
    n88["building_motor_industry<br/>lvl=0"]
    n89["building_oil_rig<br/>lvl=0"]
    n90["building_oil_rig<br/>lvl=0"]
    n91["building_oil_rig<br/>lvl=5.084 | active"]
    n92["building_paper_mill<br/>lvl=0"]
    n93["building_paper_mill<br/>lvl=0.04136 | active"]
    n94["building_paper_mill<br/>lvl=0"]
    n95["building_power_plant<br/>lvl=0"]
    n96["building_power_plant<br/>lvl=0"]
    n97["building_power_plant<br/>lvl=1.908 | active"]
    n98["building_railway<br/>lvl=1.551 | active"]
    n99["building_railway<br/>lvl=0"]
    n100["building_railway<br/>lvl=0"]
    n101["building_railway<br/>lvl=0"]
    n102["building_rice_farm<br/>lvl=0"]
    n103["building_rice_farm<br/>lvl=0"]
    n104["building_rice_farm<br/>lvl=0"]
    n105["building_rice_farm<br/>lvl=0"]
    n106["building_rice_farm<br/>lvl=0"]
    n107["building_rice_farm<br/>lvl=0"]
    n108["building_rubber_plantation<br/>lvl=0"]
    n109["building_rubber_plantation<br/>lvl=3.254 | active"]
    n110["building_rubber_plantation<br/>lvl=0"]
    n111["building_rye_farm<br/>lvl=0"]
    n112["building_rye_farm<br/>lvl=0"]
    n113["building_rye_farm<br/>lvl=0"]
    n114["building_rye_farm<br/>lvl=0"]
    n115["building_rye_farm<br/>lvl=0"]
    n116["building_rye_farm<br/>lvl=0"]
    n117["building_shipyard<br/>lvl=0"]
    n118["building_shipyard<br/>lvl=0"]
    n119["building_shipyard<br/>lvl=0"]
    n120["building_shipyard<br/>lvl=0"]
    n121["building_steel_mill<br/>lvl=0"]
    n122["building_steel_mill<br/>lvl=1.057 | active"]
    n123["building_steel_mill<br/>lvl=0"]
    n124["building_sulfur_mine<br/>lvl=0"]
    n125["building_sulfur_mine<br/>lvl=0"]
    n126["building_sulfur_mine<br/>lvl=0.07442 | active"]
    n127["building_synthetics_plant<br/>lvl=0.00517 | active"]
    n128["building_synthetics_plant<br/>lvl=0"]
    n129["building_tooling_workshop<br/>lvl=1.151 | active"]
    n130["building_tooling_workshop<br/>lvl=0"]
    n131["building_tooling_workshop<br/>lvl=0"]
    n132["building_urban_center<br/>lvl=0"]
    n133["building_urban_center<br/>lvl=0"]
    n134["building_urban_center<br/>lvl=0"]
    n4 -.->|"1.474"| n52
    n4 -->|"r=15"| n62
    n4 -->|"r=15"| n63
    n4 -->|"r=15"| n64
    n4 -.->|"4.744"| n73
    n4 -.->|"r=4"| n76
    n4 -.->|"r=5"| n77
    n4 -.->|"r=5"| n78
    n4 -.->|"r=5"| n79
    n4 -.->|"r=10"| n88
    n4 -.->|"0.4136"| n93
    n4 -.->|"r=5"| n94
    n4 -.->|"r=15"| n95
    n4 -.->|"r=5"| n96
    n4 -.->|"r=2"| n102
    n4 -.->|"r=2"| n105
    n4 -.->|"r=1"| n112
    n4 -.->|"r=1"| n115
    n4 -->|"r=10"| n120
    n4 -.->|"r=30"| n121
    n4 -.->|"42.27"| n122
    n4 -.->|"r=35"| n123
    n4 -.->|"0.2977"| n126
    n4 -.->|"r=15"| n131
    n5 -->|"r=1"| n36
    n5 -->|"r=1"| n38
    n5 -->|"r=1"| n40
    n5 -->|"r=1"| n41
    n5 -->|"20"| n42
    n5 -->|"r=1"| n62
    n5 -->|"r=1"| n63
    n5 -->|"r=1"| n64
    n5 -.->|"2.48"| n86
    n5 -.->|"r=4"| n95
    n5 -.->|"r=2"| n96
    n5 -.->|"9.542"| n97
    n5 -.->|"1.151"| n129
    n5 -.->|"r=1"| n132
    n5 -.->|"r=1"| n133
    n5 -.->|"r=1"| n134
    n6 -.->|"r=10"| n65
    n6 -.->|"r=10"| n66
    n6 -.->|"r=10"| n67
    n6 -.->|"r=5"| n68
    n6 -.->|"r=10"| n92
    n6 -.->|"0.4136"| n93
    n6 -.->|"r=10"| n94
    n7 -->|"r=5"| n36
    n7 -->|"r=5"| n38
    n7 -->|"r=5"| n40
    n7 -->|"r=5"| n41
    n7 -->|"100"| n42
    n7 -.->|"2.758"| n60
    n7 -->|"r=6"| n62
    n7 -->|"r=4"| n63
    n7 -->|"r=4"| n64
    n7 -.->|"r=1"| n77
    n7 -.->|"r=1"| n78
    n7 -.->|"r=5"| n80
    n7 -.->|"r=5"| n81
    n7 -.->|"r=5"| n82
    n7 -.->|"0.06204"| n83
    n7 -.->|"r=5"| n84
    n7 -.->|"r=5"| n85
    n7 -.->|"12.4"| n86
    n7 -.->|"r=10"| n101
    n7 -->|"r=30"| n117
    n7 -.->|"r=30"| n121
    n7 -.->|"31.7"| n122
    n7 -.->|"r=30"| n123
    n7 -.->|"5.753"| n129
    n7 -.->|"r=4"| n132
    n7 -.->|"r=4"| n133
    n7 -.->|"r=4"| n134
    n8 -->|"r=10"| n36
    n8 -->|"r=10"| n37
    n8 -->|"r=10"| n38
    n8 -->|"r=10"| n39
    n8 -->|"r=10"| n40
    n8 -->|"r=10"| n41
    n8 -->|"200"| n42
    n8 -->|"r=10"| n43
    n8 -.->|"0.4393"| n49
    n8 -.->|"0.3686"| n52
    n8 -->|"r=5"| n55
    n8 -->|"r=5"| n56
    n8 -->|"r=5"| n57
    n8 -.->|"r=5"| n58
    n8 -.->|"r=2"| n65
    n8 -.->|"r=2"| n67
    n8 -.->|"r=2"| n68
    n8 -.->|"r=2"| n69
    n8 -.->|"1.186"| n73
    n8 -.->|"r=1"| n76
    n8 -.->|"r=1"| n80
    n8 -.->|"r=1"| n81
    n8 -.->|"r=1"| n82
    n8 -.->|"0.01241"| n83
    n8 -.->|"r=1"| n84
    n8 -.->|"r=1"| n85
    n8 -.->|"r=10"| n89
    n8 -.->|"r=10"| n90
    n8 -.->|"50.84"| n91
    n8 -.->|"r=6"| n95
    n8 -.->|"r=4"| n96
    n8 -.->|"19.08"| n97
    n8 -.->|"9.306"| n98
    n8 -.->|"r=6"| n99
    n8 -.->|"r=6"| n100
    n8 -.->|"r=6"| n101
    n8 -.->|"r=5"| n108
    n8 -.->|"16.27"| n109
    n8 -.->|"r=5"| n110
    n8 -.->|"r=1"| n111
    n8 -.->|"r=1"| n114
    n8 -->|"r=10"| n117
    n8 -->|"r=5"| n119
    n8 -->|"r=10"| n120
    n8 -.->|"0.07442"| n126
    n9 -.->|"r=10"| n47
    n9 -.->|"r=10"| n48
    n9 -.->|"4.393"| n49
    n9 -.->|"r=10"| n50
    n9 -.->|"r=10"| n51
    n9 -.->|"3.686"| n52
    n9 -.->|"r=10"| n71
    n9 -.->|"r=10"| n72
    n9 -.->|"11.86"| n73
    n9 -.->|"r=10"| n74
    n9 -.->|"r=10"| n75
    n9 -.->|"r=10"| n76
    n9 -.->|"r=10"| n124
    n9 -.->|"r=10"| n125
    n9 -.->|"0.7442"| n126
    n10 -->|"r=4"| n36
    n10 -->|"r=4"| n37
    n10 -->|"r=4"| n40
    n10 -->|"r=4"| n41
    n10 -->|"r=20"| n118
    n10 -->|"r=20"| n119
    n11 -.->|"r=30"| n59
    n11 -.->|"6.894"| n60
    n11 -.->|"r=40"| n61
    n11 -.->|"r=30"| n102
    n11 -.->|"r=30"| n103
    n11 -.->|"r=30"| n104
    n11 -.->|"r=30"| n105
    n11 -.->|"r=30"| n106
    n11 -.->|"r=30"| n107
    n11 -.->|"r=15"| n111
    n11 -.->|"r=15"| n112
    n11 -.->|"r=15"| n113
    n11 -.->|"r=15"| n114
    n11 -.->|"r=15"| n115
    n11 -.->|"r=15"| n116
    n11 -.->|"0.1551"| n127
    n11 -.->|"r=30"| n128
    n15 -.->|"r=2"| n132
    n15 -.->|"r=2"| n133
    n15 -.->|"r=2"| n134
    n16 -.->|"r=15"| n77
    n16 -.->|"r=15"| n78
    n16 -.->|"r=15"| n79
    n17 -->|"r=4"| n36
    n17 -->|"r=4"| n37
    n17 -->|"r=4"| n40
    n17 -->|"r=4"| n41
    n17 -->|"r=20"| n119
    n18 -.->|"r=10"| n44
    n18 -.->|"r=30"| n45
    n18 -.->|"1.057"| n46
    n18 -.->|"r=1"| n77
    n18 -.->|"r=1"| n78
    n18 -.->|"r=1"| n79
    n18 -.->|"r=100"| n121
    n18 -.->|"105.7"| n122
    n18 -.->|"r=100"| n123
    n19 -.->|"r=35"| n65
    n19 -.->|"r=35"| n66
    n19 -.->|"r=30"| n68
    n19 -.->|"r=30"| n69
    n19 -.->|"r=30"| n70
    n22 -->|"r=10"| n36
    n22 -->|"r=5"| n37
    n22 -->|"r=10"| n38
    n22 -->|"r=5"| n39
    n22 -->|"r=15"| n40
    n22 -->|"r=15"| n41
    n22 -->|"300"| n42
    n22 -->|"r=10"| n43
    n22 -.->|"0.7049"| n46
    n22 -.->|"r=5"| n47
    n22 -.->|"r=5"| n48
    n22 -.->|"2.196"| n49
    n22 -.->|"r=5"| n50
    n22 -.->|"r=5"| n51
    n22 -.->|"1.843"| n52
    n22 -.->|"r=5"| n65
    n22 -.->|"r=5"| n67
    n22 -.->|"r=25"| n68
    n22 -.->|"r=25"| n69
    n22 -.->|"r=20"| n70
    n22 -.->|"r=5"| n71
    n22 -.->|"r=5"| n72
    n22 -.->|"5.929"| n73
    n22 -.->|"r=5"| n74
    n22 -.->|"r=5"| n75
    n22 -.->|"r=5"| n76
    n22 -.->|"r=4"| n80
    n22 -.->|"r=4"| n81
    n22 -.->|"r=4"| n82
    n22 -.->|"0.04964"| n83
    n22 -.->|"r=4"| n84
    n22 -.->|"r=4"| n85
    n22 -.->|"136.4"| n86
    n22 -.->|"r=50"| n87
    n22 -.->|"r=50"| n88
    n22 -.->|"38.17"| n97
    n22 -.->|"12.41"| n98
    n22 -.->|"r=8"| n99
    n22 -.->|"r=8"| n100
    n22 -.->|"r=2"| n111
    n22 -.->|"r=2"| n114
    n22 -.->|"r=5"| n124
    n22 -.->|"r=5"| n125
    n22 -.->|"0.3721"| n126
    n22 -.->|"10.35"| n129
    n23 -.->|"r=10"| n59
    n23 -.->|"4.136"| n60
    n23 -.->|"r=20"| n61
    n25 -->|"r=5"| n36
    n25 -->|"r=5"| n37
    n25 -->|"r=5"| n38
    n25 -->|"r=5"| n39
    n25 -->|"r=10"| n40
    n25 -->|"r=10"| n41
    n25 -->|"200"| n42
    n25 -->|"r=10"| n43
    n25 -.->|"11.51"| n129
    n25 -.->|"r=10"| n130
    n25 -.->|"r=10"| n131
    n28 -->|"r=5"| n62
    n28 -->|"r=5"| n63
    n28 -->|"r=5"| n64
    n29 -->|"r=5"| n38
    n29 -->|"r=5"| n39
    n29 -->|"r=5"| n41
    n29 -.->|"124"| n86
    n29 -.->|"r=50"| n87
    n29 -.->|"r=50"| n88
    n29 -.->|"r=5"| n99
    n29 -.->|"r=5"| n101
    n29 -->|"r=30"| n117
    n29 -->|"r=30"| n120
    n29 -.->|"34.52"| n129
    n29 -.->|"r=30"| n130
    n29 -.->|"r=30"| n131
    n29 -.->|"r=1"| n132
    n29 -.->|"r=1"| n133
    n29 -.->|"r=1"| n134
    n31 -.->|"r=30"| n44
    n31 -.->|"r=30"| n45
    n31 -.->|"1.41"| n46
    n31 -.->|"r=30"| n59
    n31 -.->|"5.515"| n60
    n31 -.->|"r=40"| n61
    n31 -.->|"r=10"| n92
    n31 -.->|"0.4136"| n93
    n31 -.->|"r=10"| n94
    n31 -.->|"0.1034"| n127
    n31 -.->|"r=20"| n128
    n33 -->|"r=4"| n36
    n33 -->|"r=4"| n38
    n33 -->|"r=4"| n40
    n33 -->|"r=4"| n41
    n33 -->|"80"| n42
    n33 -.->|"r=15"| n47
    n33 -.->|"r=15"| n48
    n33 -.->|"6.589"| n49
    n33 -.->|"r=15"| n50
    n33 -.->|"r=15"| n51
    n33 -.->|"5.529"| n52
    n33 -.->|"r=2"| n65
    n33 -.->|"r=2"| n67
    n33 -.->|"r=2"| n68
    n33 -.->|"r=2"| n69
    n33 -.->|"r=15"| n71
    n33 -.->|"r=15"| n72
    n33 -.->|"17.79"| n73
    n33 -.->|"r=15"| n74
    n33 -.->|"r=15"| n75
    n33 -.->|"r=15"| n76
    n33 -.->|"r=5"| n77
    n33 -.->|"r=5"| n78
    n33 -.->|"r=5"| n79
    n33 -.->|"r=10"| n80
    n33 -.->|"r=10"| n81
    n33 -.->|"r=10"| n82
    n33 -.->|"0.1241"| n83
    n33 -.->|"r=10"| n84
    n33 -.->|"r=10"| n85
    n33 -.->|"9.919"| n86
    n33 -.->|"r=5"| n88
    n33 -.->|"0.2068"| n93
    n33 -.->|"r=5"| n94
    n33 -.->|"r=4"| n102
    n33 -.->|"r=4"| n103
    n33 -.->|"r=4"| n105
    n33 -.->|"r=4"| n106
    n33 -.->|"r=2"| n112
    n33 -.->|"r=2"| n113
    n33 -.->|"r=2"| n115
    n33 -.->|"r=2"| n116
    n33 -.->|"5.284"| n122
    n33 -.->|"r=5"| n123
    n33 -.->|"r=15"| n124
    n33 -.->|"r=15"| n125
    n33 -.->|"1.116"| n126
    n34 -.->|"r=5"| n47
    n34 -.->|"2.196"| n49
    n34 -.->|"r=5"| n50
    n34 -.->|"1.843"| n52
    n34 -->|"r=5"| n56
    n34 -->|"r=7"| n62
    n34 -->|"r=5"| n63
    n34 -.->|"r=5"| n71
    n34 -.->|"5.929"| n73
    n34 -.->|"r=5"| n74
    n34 -.->|"r=5"| n76
    n34 -.->|"r=1"| n77
    n34 -.->|"r=8"| n80
    n34 -.->|"r=5"| n81
    n34 -.->|"0.09927"| n83
    n34 -.->|"r=5"| n84
    n34 -.->|"r=5"| n89
    n34 -.->|"50.84"| n91
    n34 -.->|"16.27"| n109
    n34 -.->|"r=5"| n124
    n34 -.->|"0.3721"| n126
    n35 -.->|"r=30"| n67
    n35 -.->|"r=30"| n92
    n35 -.->|"1.241"| n93
    n35 -.->|"r=30"| n94
    n35 -.->|"r=8"| n100
    n35 -->|"r=40"| n118
    n35 -->|"r=20"| n119
    n35 -.->|"r=10"| n128
    n36 -->|"r=10"| n0
    n36 -->|"r=20"| n1
    n37 -->|"r=10"| n0
    n37 -->|"r=20"| n1
    n38 -->|"r=10"| n1
    n38 -->|"r=20"| n32
    n39 -->|"r=10"| n1
    n39 -->|"r=20"| n32
    n40 -->|"r=10"| n0
    n40 -->|"r=40"| n1
    n41 -->|"r=10"| n0
    n41 -->|"r=20"| n1
    n41 -->|"r=20"| n32
    n42 -->|"1000"| n1
    n43 -->|"r=50"| n1
    n44 -.->|"r=90"| n11
    n45 -.->|"r=140"| n11
    n46 -.->|"7.049"| n11
    n47 -.->|"r=115"| n4
    n48 -.->|"r=115"| n4
    n49 -.->|"49.2"| n4
    n50 -.->|"r=90"| n5
    n51 -.->|"r=90"| n5
    n52 -.->|"33.17"| n5
    n53 -->|"r=0.25"| n3
    n53 -->|"r=3"| n10
    n53 -->|"r=0.25"| n14
    n53 -->|"r=5"| n16
    n53 -->|"r=0.25"| n20
    n53 -->|"r=4"| n21
    n53 -->|"r=0.25"| n26
    n53 -->|"r=0.5"| n35
    n54 -->|"r=0.25"| n3
    n54 -->|"r=3"| n10
    n54 -->|"r=0.25"| n14
    n54 -->|"r=5"| n16
    n54 -->|"r=0.25"| n20
    n54 -->|"r=4"| n21
    n54 -->|"r=0.25"| n26
    n54 -->|"r=0.5"| n35
    n55 -->|"r=100"| n10
    n56 -->|"r=100"| n10
    n57 -->|"r=90"| n10
    n58 -.->|"r=60"| n6
    n59 -.->|"r=80"| n9
    n60 -.->|"20.68"| n9
    n61 -.->|"r=110"| n9
    n62 -->|"r=100"| n12
    n63 -->|"r=100"| n12
    n64 -->|"r=100"| n12
    n65 -.->|"r=40"| n15
    n65 -->|"r=30"| n24
    n66 -.->|"r=40"| n15
    n66 -->|"r=30"| n24
    n67 -.->|"r=10"| n15
    n67 -->|"r=30"| n24
    n68 -.->|"r=90"| n15
    n68 -->|"r=10"| n24
    n69 -.->|"r=100"| n15
    n70 -.->|"r=100"| n15
    n71 -.->|"r=90"| n18
    n72 -.->|"r=90"| n18
    n73 -.->|"106.7"| n18
    n74 -.->|"r=90"| n19
    n75 -.->|"r=90"| n19
    n76 -.->|"r=90"| n19
    n77 -->|"r=25"| n10
    n77 -.->|"r=5"| n11
    n77 -->|"r=35"| n21
    n78 -->|"r=25"| n10
    n78 -.->|"r=5"| n11
    n78 -->|"r=35"| n21
    n79 -->|"r=25"| n10
    n79 -.->|"r=5"| n11
    n79 -->|"r=35"| n21
    n80 -->|"r=20"| n17
    n80 -.->|"r=60"| n35
    n81 -->|"r=20"| n17
    n81 -.->|"r=60"| n35
    n82 -->|"r=20"| n17
    n82 -.->|"r=60"| n35
    n83 -.->|"1.241"| n35
    n84 -.->|"r=100"| n35
    n85 -.->|"r=100"| n35
    n86 -.->|"297.6"| n8
    n87 -.->|"r=120"| n8
    n88 -.->|"r=120"| n8
    n89 -.->|"r=100"| n22
    n90 -.->|"r=100"| n22
    n91 -.->|"508.4"| n22
    n92 -.->|"r=100"| n23
    n93 -.->|"4.136"| n23
    n94 -.->|"r=100"| n23
    n95 -.->|"r=50"| n7
    n96 -.->|"r=25"| n7
    n97 -.->|"152.7"| n7
    n98 -.->|"77.55"| n34
    n99 -.->|"r=65"| n34
    n100 -.->|"r=60"| n34
    n101 -.->|"r=60"| n34
    n102 -->|"r=15"| n13
    n102 -.->|"r=80"| n16
    n102 -->|"r=2"| n30
    n103 -->|"r=15"| n13
    n103 -.->|"r=80"| n16
    n103 -->|"r=2"| n30
    n104 -->|"r=15"| n13
    n104 -.->|"r=80"| n16
    n104 -->|"r=2"| n30
    n105 -.->|"r=100"| n16
    n106 -.->|"r=100"| n16
    n107 -.->|"r=100"| n16
    n108 -.->|"r=65"| n25
    n109 -.->|"211.5"| n25
    n110 -.->|"r=50"| n25
    n111 -.->|"r=50"| n16
    n111 -->|"r=10"| n20
    n112 -.->|"r=50"| n16
    n112 -->|"r=10"| n20
    n113 -.->|"r=50"| n16
    n113 -->|"r=10"| n20
    n114 -.->|"r=55"| n16
    n114 -->|"r=4"| n30
    n115 -.->|"r=55"| n16
    n115 -->|"r=4"| n30
    n116 -.->|"r=55"| n16
    n116 -->|"r=4"| n30
    n117 -->|"r=80"| n28
    n118 -->|"r=40"| n2
    n119 -->|"r=70"| n2
    n120 -->|"r=65"| n28
    n121 -.->|"r=150"| n29
    n122 -.->|"158.5"| n29
    n123 -.->|"r=150"| n29
    n124 -.->|"r=100"| n31
    n125 -.->|"r=100"| n31
    n126 -.->|"7.442"| n31
    n127 -.->|"0.4136"| n6
    n128 -.->|"r=70"| n6
    n128 -->|"r=30"| n27
    n129 -.->|"126.6"| n33
    n130 -.->|"r=110"| n33
    n131 -.->|"r=110"| n33
    n132 -->|"r=40"| n26
    n132 -.->|"r=2"| n34
    n133 -->|"r=40"| n26
    n133 -.->|"r=2"| n34
    n134 -->|"r=40"| n26
    n134 -.->|"r=2"| n34
    class n4,n5,n6,n7,n8,n9,n11,n15,n16,n18,n19,n22,n23,n25,n29,n31,n33,n34,n35,n44,n45,n46,n47,n48,n49,n50,n51,n52,n58,n59,n60,n61,n65,n66,n67,n68,n69,n70,n71,n72,n73,n74,n75,n76,n77,n78,n79,n80,n81,n82,n83,n84,n85,n86,n87,n88,n89,n90,n91,n92,n93,n94,n95,n96,n97,n98,n99,n100,n101,n102,n103,n104,n105,n106,n107,n108,n109,n110,n111,n112,n113,n114,n115,n116,n121,n122,n123,n124,n125,n126,n127,n128,n129,n130,n131,n132,n133,n134 cyclic
    class n47,n48,n49,n50,n51,n52,n62,n63,n64,n71,n72,n73,n74,n75,n76,n80,n81,n82,n83,n84,n85,n89,n90,n91,n108,n109,n110,n124,n125,n126 resource
    class n42,n46,n49,n52,n60,n73,n83,n86,n91,n93,n97,n98,n109,n122,n126,n127,n129 active
    classDef cyclic stroke:#d97706,stroke-width:2px
    classDef resource fill:#dcfce7,stroke:#15803d
    classDef active fill:#dbeafe,stroke:#1d4ed8

Realized automobile chain:

flowchart LR
    n0(("automobiles ★"))
    n1(("coal"))
    n2(("copper"))
    n3(("dye"))
    n4(("electricity"))
    n5(("engines"))
    n6(("explosives"))
    n7(("fertilizer"))
    n8(("iron"))
    n9(("oil"))
    n10(("paper"))
    n11(("rubber"))
    n12(("steel"))
    n13(("sulfur"))
    n14(("tools"))
    n15(("transportation"))
    n16(("wood"))
    n17["building_automotive_industry<br/>lvl=20 | active"]
    n18["building_chemical_plant<br/>lvl=0.03524 | active"]
    n19["building_coal_mine<br/>lvl=0.4393 | active"]
    n20["building_copper_mine<br/>lvl=0.3686 | active"]
    n21["building_explosives_factory<br/>lvl=0.1379 | active"]
    n22["building_iron_mine<br/>lvl=1.186 | active"]
    n23["building_logging_camp<br/>lvl=0.01241 | active"]
    n24["building_motor_industry<br/>lvl=2.48 | active"]
    n25["building_oil_rig<br/>lvl=5.084 | active"]
    n26["building_paper_mill<br/>lvl=0.04136 | active"]
    n27["building_power_plant<br/>lvl=1.908 | active"]
    n28["building_railway<br/>lvl=1.551 | active"]
    n29["building_rubber_plantation<br/>lvl=3.254 | active"]
    n30["building_steel_mill<br/>lvl=1.057 | active"]
    n31["building_sulfur_mine<br/>lvl=0.07442 | active"]
    n32["building_synthetics_plant<br/>lvl=0.00517 | active"]
    n33["building_tooling_workshop<br/>lvl=1.151 | active"]
    n1 -.->|"1.474"| n20
    n1 -.->|"4.744"| n22
    n1 -.->|"0.4136"| n26
    n1 -.->|"42.27"| n30
    n1 -.->|"0.2977"| n31
    n2 -->|"20"| n17
    n2 -.->|"2.48"| n24
    n2 -.->|"9.542"| n27
    n2 -.->|"1.151"| n33
    n3 -.->|"0.4136"| n26
    n4 -->|"100"| n17
    n4 -.->|"2.758"| n21
    n4 -.->|"0.06204"| n23
    n4 -.->|"12.4"| n24
    n4 -.->|"31.7"| n30
    n4 -.->|"5.753"| n33
    n5 -->|"200"| n17
    n5 -.->|"0.4393"| n19
    n5 -.->|"0.3686"| n20
    n5 -.->|"1.186"| n22
    n5 -.->|"0.01241"| n23
    n5 -.->|"50.84"| n25
    n5 -.->|"19.08"| n27
    n5 -.->|"9.306"| n28
    n5 -.->|"16.27"| n29
    n5 -.->|"0.07442"| n31
    n6 -.->|"4.393"| n19
    n6 -.->|"3.686"| n20
    n6 -.->|"11.86"| n22
    n6 -.->|"0.7442"| n31
    n7 -.->|"6.894"| n21
    n7 -.->|"0.1551"| n32
    n8 -.->|"1.057"| n18
    n8 -.->|"105.7"| n30
    n9 -->|"300"| n17
    n9 -.->|"0.7049"| n18
    n9 -.->|"2.196"| n19
    n9 -.->|"1.843"| n20
    n9 -.->|"5.929"| n22
    n9 -.->|"0.04964"| n23
    n9 -.->|"136.4"| n24
    n9 -.->|"38.17"| n27
    n9 -.->|"12.41"| n28
    n9 -.->|"0.3721"| n31
    n9 -.->|"10.35"| n33
    n10 -.->|"4.136"| n21
    n11 -->|"200"| n17
    n11 -.->|"11.51"| n33
    n12 -.->|"124"| n24
    n12 -.->|"34.52"| n33
    n13 -.->|"1.41"| n18
    n13 -.->|"5.515"| n21
    n13 -.->|"0.4136"| n26
    n13 -.->|"0.1034"| n32
    n14 -->|"80"| n17
    n14 -.->|"6.589"| n19
    n14 -.->|"5.529"| n20
    n14 -.->|"17.79"| n22
    n14 -.->|"0.1241"| n23
    n14 -.->|"9.919"| n24
    n14 -.->|"0.2068"| n26
    n14 -.->|"5.284"| n30
    n14 -.->|"1.116"| n31
    n15 -.->|"2.196"| n19
    n15 -.->|"1.843"| n20
    n15 -.->|"5.929"| n22
    n15 -.->|"0.09927"| n23
    n15 -.->|"50.84"| n25
    n15 -.->|"16.27"| n29
    n15 -.->|"0.3721"| n31
    n16 -.->|"1.241"| n26
    n17 -->|"1000"| n0
    n18 -.->|"7.049"| n7
    n19 -.->|"49.2"| n1
    n20 -.->|"33.17"| n2
    n21 -.->|"20.68"| n6
    n22 -.->|"106.7"| n8
    n23 -.->|"1.241"| n16
    n24 -.->|"297.6"| n5
    n25 -.->|"508.4"| n9
    n26 -.->|"4.136"| n10
    n27 -.->|"152.7"| n4
    n28 -.->|"77.55"| n15
    n29 -.->|"211.5"| n11
    n30 -.->|"158.5"| n12
    n31 -.->|"7.442"| n13
    n32 -.->|"0.4136"| n3
    n33 -.->|"126.6"| n14
    class n1,n2,n3,n4,n5,n6,n7,n8,n9,n10,n11,n12,n13,n14,n15,n16,n18,n19,n20,n21,n22,n23,n24,n25,n26,n27,n28,n29,n30,n31,n32,n33 cyclic
    class n19,n20,n22,n23,n25,n29,n31 resource
    class n17,n18,n19,n20,n21,n22,n23,n24,n25,n26,n27,n28,n29,n30,n31,n32,n33 active
    classDef cyclic stroke:#d97706,stroke-width:2px
    classDef resource fill:#dcfce7,stroke:#15803d
    classDef active fill:#dbeafe,stroke:#1d4ed8

Realized era 5 automobile supply-chain network with edges weighted by base-price value

Era 5 automation: realized automobile network, with edge widths weighted by weekly base-price value (£).

Cycles represent real feedback. For example, oil extraction can consume engines while motor industries consume oil. A traversal cutoff does not turn either good into a free resource. Check the quantitative flows rather than inferring requirements from graph depth.

The regenerated era 5 automobile network contains 16 processes, 16 goods, and 77 edges, with one cyclic component. The allowed graph includes many more alternatives, so a pruned diagram cannot establish their total count.

Compare contributions

contributions_gdp.svg, contributions_employment.svg, and contributions_construction_cost.svg show leading whole-process contributions to the terminal chain. The same process can matter very differently for labor, construction, and value added.

Leading process contributions to weekly GDP in the era 5 automobile chain

Era 5 automation: leading automobile-chain contributions to weekly value added (£).

Leading process contributions to employment in the era 5 automobile chain

Era 5 automation: leading automobile-chain employment contributions, in workers.

Leading process contributions to construction cost in the era 5 automobile chain

Era 5 automation: leading automobile-chain construction contributions, in construction points.

For the era 5 automobile chain, automotive assembly employs 70,000 workers and requires 16,000 construction points. The upstream chain therefore accounts for another 55,161 workers. Rubber plantations employ about 16,392 workers but require only 655.7 construction points; oil rigs employ 15,590 workers and require 2,078.7 points. Their relative importance changes between the employment and construction charts. Machinists and engineers together account for 73.9% of chain employment, which illustrates why a small total workforce can still depend heavily on skilled professions.

Era 5 automobile-chain employment by profession

Era 5 automation: automobile-chain workforce by profession, in workers.

Chain totals include whole selected processes, including their coproducts; they do not allocate a factory's workers or construction uniquely to one good. Whole-system totals can also include activity outside the graph-defined chain. Weekly value added is output base value minus intermediate input base cost; annual GDP is 52 times weekly GDP.

Goods & scenario sweep

The combined summary is artifacts/analyses/supply_chains/comparison/summary.csv. It contains one row per good/configuration pair selected in the current run, in requested good order and then configuration order. It retains failures. Each configuration has one summary.csv combining its selected goods, for example analyses/supply_chains/era_5_automation/summary.csv. It records each good's target, objective, solver status, whole-system totals, chain totals, and configuration labels. No summary files are written inside the individual good directories. Use a single configuration when ranking goods under common assumptions.

good configuration status chain_gdp_per_capita_annual chain_wage_normalized_employment chain_levels_building_coal_mine chain_levels_per_10k_pop_building_coal_mine
ammunition era_3_construction success 7.925092066941082 1143356.0306570823 3.1222958678599477 0.03482277256028827
ammunition era_5_automation success 29.222049157420226 382442.64892258786 0.9727341863745714 0.05466401194488629
ammunition cangshulun success 25.71254709280572 410304.48677220684 4.114864422854238 0.203468548563751
small_arms era_3_construction success 6.069145869707615 1764288.4707792674 2.7551309265974004 0.018191127267855278
small_arms era_5_automation success 40.36656246940272 271104.334062767 1.4176454040431872 0.11004898415725188

Download all-good comparison

The comparison directory contains this summary and three grouped bar charts:

  • pop.svg plots system_employment, the whole-system employed population in workers. It excludes dependents and unemployed people.
  • construction_points.svg plots system_construction_cost in construction points.
  • gdp_per_capita.svg plots system_gdp_per_capita_annual: annual system GDP divided by system employment, in £ per worker per year. Zero employment gives zero, matching the economy model's GDP-per-capita convention.

All charts use goods as the main horizontal-axis ticks, with configuration ticks beneath the individual bars. Colors identify configurations consistently between charts. A failed solve keeps its tick and shows an × instead of a bar; it is not treated as a zero requirement. SVG width grows with the number of goods so the two tick levels remain readable when zoomed.

Whole-system employment by terminal good across the three supply-chain configurations

All three configurations: whole-system employment by terminal good, in workers.

Whole-system construction requirements by terminal good across the three supply-chain configurations

All three configurations: whole-system construction requirements by terminal good, in construction points.

Annual GDP per employed worker by terminal good across the three supply-chain configurations

All three configurations: annual whole-system GDP per employed worker, in £ per worker per year.

Click any chart to open the original SVG and zoom in on its labels.

Population chart · Construction chart · Annual GDP per capita chart

from pathlib import Path
import pandas as pd

comparison = pd.read_csv(
    Path("artifacts/analyses/supply_chains/comparison/summary.csv")
)
successful = comparison.loc[
    comparison["configuration"].eq("era_5_automation")
    & comparison["status"].eq("success")
]
lowest_employment = successful.sort_values(
    ["system_employment", "good"], kind="stable"
).head(10)

Sorting the automation rows by construction answers which of those minimum-employment chains uses least construction. It does not compute a minimum-construction optimum for each good.

Reproducing Cangshulun's video

Apart from the video mentioned above, the uploader also made a follow-up video running a complete supply chain analysis for all goods on the 1.12 patch. His methodology is not mathematic programming, but rather a leontief matrix approach, where production units are selected manually. To reproduce his results, the examples/supply_chain_cangshulun.py script adds throughput bonuses, production-method bans, and named product variants to approximate the video's assumptions.

uv run python -m examples.supply_chain_cangshulun

The script writes the latest complete results to artifacts/analyses/supply_chains/cangshulun_video/summary.csv. The frozen artifacts/analyses/supply_chains/cangshulun_video/summary_1.12.csv contains 60 scenarios from the 1.12.5 results, extracted from artifact commit e7a3748964cf28f453db1899f08636eb04c45d71 and sorted by annual value added per worker. It retains only the columns used for the video comparison:

  • scenario
  • system_gdp_annual
  • system_employment
  • system_gdp_per_capita_annual
  • system_levels_per_10k_pop_building_sulfur_mine
  • system_levels_per_10k_pop_building_coal_mine
  • system_levels_per_10k_pop_building_iron_mine
  • system_levels_per_10k_pop_building_lead_mine
  • system_levels_per_10k_pop_building_logging_camp
  • system_levels_per_10k_pop_building_rubber_plantation
  • system_levels_per_10k_pop_building_oil_rig

The video's table at 1:04 is reproduced below. Its total value column is weekly, so compare it with system_gdp_annual / 52; its per-worker value is annual and corresponds to system_gdp_per_capita_annual. Resource columns measure building levels per 10,000 employed workers. Our runs target £100,000 of weekly terminal output, so raw value and employment totals have a different scale from the screenshot; compare the per-worker and per-10,000-worker ratios.

Cangshulun's patch 1.12.4 supply-chain table at 1:04, showing annual value added per worker and resource-building levels per 10,000 workers

Source: Cangshulun's video, 1:04. Click the image to inspect the full table.

scenario system_gdp_per_capita_annual system_levels_per_10k_pop_building_coal_mine system_levels_per_10k_pop_building_oil_rig
base:oil 108.919629312571 0.036890872165386 2.64369000668648
base:sulfur 103.356087210857 0.105249157282333 0.220526906758574
base:transportation 100.468515120695 0.0550937550952978 0.738706498450207
base:electricity 100.271318402311 0.0638803510830851 1.24121037351983
base:merchant_marine 92.1092956591867 0.0451802533435092 0.680902530759515

The following examples compare annual nominal value added per employed worker (£/worker/year). Difference means (project / video - 1) * 100%.

Supply chain Video 1.12.4 Project 1.12.5 Difference
Oil 107.99 108.92 +0.9%
Sulfur 102.31 103.36 +1.0%
Automobiles 87.47 88.86 +1.6%
Engines 84.68 86.90 +2.6%
Tools 78.82 80.93 +2.7%
Coal-fired electricity 73.08 73.14 +0.1%
Rubber 32.11 32.21 +0.3%
Luxury furniture + surplus wood 63.60 57.86 −9.0%
Fine art 36.80 37.32 +1.4%
Urban services + transportation 26.55 26.83 +1.1%

The electricity, luxury-furniture, and urban-service rows use the coal_fired_plant:electricity, luxury_furniture:luxury_furniture, and urban_center_transportation:services scenarios respectively; the other rows use base:<good> scenarios. Most rows shown agree within 3%, supporting the video's broad productivity ranking, except for luxury furniture, which remains 9.0% lower. Production-method and coproduct choices can differ because the optimizer selects a minimum-employment chain rather than the video's fixed recipe.

Download 1.12 selected results (1.12.5 inputs) · Download latest complete results (1.13.11) · View examples/supply_chain_cangshulun.py

Output inventory

Paths are relative to --output-dir. All text outputs use UTF-8 without a BOM. The comparison writes one detailed result at a time rather than retaining all goods' graphs and snapshots in memory.

Directory Files
analyses/supply_chains/era_3_construction/<good>/ Detailed files below for successful solves
analyses/supply_chains/era_5_automation/<good>/ Same reports, plots, and diagrams
analyses/supply_chains/cangshulun/<good>/ Same reports, plots, and diagrams
analyses/supply_chains/<configuration>/ summary.csv, combining that configuration's selected goods, and building_levels.csv, the complete production-unit levels for each selected good
analyses/supply_chains/comparison/ summary.csv, pop.svg, construction_points.svg, gdp_per_capita.svg, covering all selected goods and presets
analyses/supply_chains/cangshulun_video/ Latest complete summary.csv and frozen selected-column summary_1.12.csv; ordinary generation updates only summary.csv

Each successful comparison configuration contains goods.csv, processes.csv, flows.csv, workforce.csv, constraints.csv, bottlenecks.csv, alternatives.csv, supply_chain_recipe.mmd, supply_chain_realised.mmd, network.svg, goods_balance.svg, workforce.svg, constraints.svg, contributions_gdp.svg, contributions_employment.svg, and contributions_construction_cost.svg. Headline metrics and failure rows are stored only in the configuration-level summary.csv and comparison CSVs.

The configuration summary and comparison CSVs use the public sweep schema, plus configuration and ban_config. GDP efficiency and per-building resource levels, including levels per 10,000 employed workers, are public summary fields shared with the video export. The other detailed CSVs retain their public report schemas. Cross-good summaries sit at configuration level. A selected-good run replaces the configuration summaries and combined comparison with that run's selection; other goods' directories remain. Each configuration's building_levels.csv is also replaced for that selection. Its first column, config, identifies the building and PM combination, followed by one column per selected good. Unused production units have zero levels; failed solves have blank cells throughout their good's column.