#Thread for LP nonsense!

1 messages · Page 1 of 1 (latest)

dapper parrot
#

Created

#

What solver setup are you using? I usually use sagemath

distant igloo
#

I'm using the sage 'get_solver' API but all of the setup is handrolled Python code

dapper parrot
#

Nice. So it doesn’t know about blue belts because they have a fluid ingredient?

#

Or just not coded in yet

distant igloo
#

I've manually added recipes, because IME adding every recipe in the game makes it impossible to understand if the code is doing the right thing

#

I added a bunch of belts because I suspected they would be useful, but didn't bother to do blue belts

dapper parrot
#

Ok that makes sense

#

Neat, so belts are one of the best options for an early game grind

distant igloo
#

Yup

#

Another thing I keep seeing is buildings with one quality module in them. Apparently the first one is "more cost effective" than the later ones?

#

pretty sure this drastically increases the material consumption, though... let me try a hybrid cost metric

dapper parrot
#

Hm yeah. I guess getting a little qual at multiple steps might stack better than a lot in one step? Though I would think that would kick in past 10% qual

distant igloo
#

the weird thing is that it's still using it only in one step. it's just using four buildings with one module each instead of one with four modules

#

maybe this is literally just the speed penalty

dapper parrot
#

Oh yeah probably that. If you’re trying to do it in one step instead of a loop

#

Or if it’s a loop but the main path is to get lucky in one step

distant igloo
#

okay, if I mix in some ore cost, then I start to get normal looking setups. e.g. to make rare module 2s, you use quality just at the ending step and recycle the low-quality results.

dapper parrot
#

ok that makes sense

#

any idea how asteroid crushing compares?

#

you only get two modules but there's a lower chance of losing stuff

distant igloo
#

I could try it out. give me a few minutes, that's a lot of recipes to add...

dapper parrot
#

could just add reprocessing and crush-to-iron

distant igloo
#

the script is definitely interested in those recipes

#

it's using an unholy mix of stuff, but asteroid crushing is in there

dapper parrot
#

yeah figures. LP

#

especially because asteroid crushing makes ore

#

you could make rare ore, but if logistics are free (because LP) it's probably better to make a mix and then have a chance to upgrade later

#

and when you get lucky and hit rare then you use prodded furnaces, but when you don't get lucky you use qual ones, and then ...

distant igloo
#

hmm. I'm seeing that you should recycle the low-tier asteroids but reprocess the high-tier ones

#

recycling is more lossy but WAY faster, so that makes some sense

dapper parrot
#

oh huh that makes sense

#

because asteroids are almost free

distant igloo
#

I wouldn't trust the exact tradeoff the LP is making, but it seems plausible in general

#

recyclers are also furnaces, which is convenient if you ask me

#

yeah, I'm pretty consistently getting "recycle normal tier, reprocess higher tiers". though sometimes I see weird things like "reprocess normal non-metallic without quality, then recycle metallic with quality". presumably this is to avoid making high quality non-metallic asteroids? not sure I trust that

distant igloo
#

maybe I should investigate beacons...

#

uh-oh, it's using beacons...

In [557]: quality.do_lp({"legendary/stone-brick": 1.0})
Out[557]: 
{'solver': <sage.numerical.backends.glpk_backend.GLPKBackend object at 0x7fa653538fa0>,
 'objective': -541.663205999954,
 'rates': {"stone/big-miner/('empty-slot', 'empty-slot', 'empty-slot')/normal": 4756.611544620971,
  "stone-brick/electric-furnace/('empty-slot', 'empty-slot')/normal": 19026.446178483882,
  "wall/assembler-3/('empty-slot', 'empty-slot', 'empty-slot', 'empty-slot')/normal": 617.140648020885,
  "wall/assembler-3/('rare/quality-2', 'rare/quality-2', 'rare/quality-2', 'rare/quality-2')/uncommon": 17.787758798866943,
  "wall/assembler-3/('rare/quality-2', 'rare/quality-2', 'rare/quality-2', 'rare/quality-2')/rare": 2.8819057801495034,
  "wall/assembler-3/('rare/quality-2', 'rare/quality-2', 'rare/quality-2', 'rare/quality-2')/epic": 0.5397828317058248,
  "recycle-wall/recycler/('empty-slot', 'empty-slot', 'empty-slot', 'empty-slot')/legendary": 0.032187231926702226,
  "recycle-wall/recycler/('rare/quality-2', 'rare/quality-2', 'rare/quality-2', 'rare/quality-2')/uncommon": 4.8471642726912405,
  "recycle-wall/recycler/('rare/quality-2', 'rare/quality-2', 'rare/quality-2', 'rare/quality-2')/rare": 1.4256786418499485,
  "recycle-wall/recycler/('rare/quality-2', 'rare/quality-2', 'rare/quality-2', 'rare/quality-2')/epic": 0.3148753614011402,
  "recycle-wall/recycler/('rare/quality-2', 'rare/quality-2', 'rare/quality-2', 'rare/quality-2', 'rare/speed-2', 'rare/speed-2', 'rare/speed-2')/normal": 86.09663058327078}}
#

⚠️ speed and quality ⚠️

dapper parrot
#

hm neat even though it hurts quality

#

i found with asteroid flipping that in theory speed beacons help, but in practice you lose time to insert and remove stuff so it might not really help

#

i'm trying to test asteroid recycling. it's hard to feed it enough asteroids tho

distant igloo
#

Yeah, the recipe is crazy fast

#

If you can't make full use of one recycler it might not be a win

dapper parrot
#

so, with some fiddling: I think it is better in theory but my ship isn't fast enough

#

and i should wind down and head to bed instead of fiddling with it more tonight

#

but yeah if you have a ship that is collecting excess asteroids it's probably better to recycle some/all of them at normal, and reprocess at uncommon+

fathom iron
#

cool thread!

fathom iron
distant igloo
#

Very cool!

#

The annoying thing about LP is that it has no chill. By which I mean it doesn't care about simplicity at all, and it spits out things that are very hard to understand. Actually making it balanced IRL can be really hard (for instance, what do you do if you end up skewed from the expected recycling probabilities?)

upbeat hatch
#

OK, so, according to my script, Kovarex would be as following with 0%/100% productivity

#

... time to see why

#

Ah, OK.

#

Multiplying the ingredients probably doesn't make sense

#

This seems more sensible

fathom iron
#

I don't think they'd be ints

upbeat hatch
#

At 100% productivity?

fathom iron
#

oh at 100 yes

upbeat hatch
#

It's 1.0, not 1%

#

For 0.5 you get 41.5, as expected

#

OK, this looks decent

#

I suppose I'll have to expand it in order to get the module slots and so forth properly done

#

Because for you, basically every combination of (machine, recipe) is an own "recipe", isn't it?

fathom iron
#

yes, you could run it with all combinations, or you could pick which machine you'd use with each crafting group

upbeat hatch
#

Yeah, but we're going for the full expansion for now

#

Filtering can come later

#

Hm, still, this is tricky

#

I suppose I'll just have to cheat a bit

#

can I even cheat?

#

Yeah, I don't think I can, given that the items can be differing

#

Since the output of an ingredient is depending on the productivity, and is not linear, I can't really set an expected value, can I?

#

If we're using Kovarex, the expected value is anything between 41 at 0% productivity, and I suppose 44 at 300%?

#

But that depends on the prod modules you throw in, which I can't control

#

I don't think we can really model that with the current data model of yours?

#

This would be the current state of the thing - I added more properties to the amount to show the different expectations at 0/50/100/250% prod

#

Kovarex is, as expected, weird

#
{
  "key": "centrifuge#kovarex-enrichment-process",
  "allow_productivity": true,
  "module_slots": 2,
  "additional_prod": 0,
  "ingredients": [
    {
      "name": "uranium-235",
      "amount": 40
    },
    {
      "name": "uranium-238",
      "amount": 5
    }
  ],
  "results": [
    {
      "name": "uranium-235",
      "amount": 41,
      "amount_50": 41.5,
      "amount_100": 42,
      "amount_250": 43.5
    },
    {
      "name": "uranium-238",
      "amount": 2,
      "amount_50": 2,
      "amount_100": 2,
      "amount_250": 2
    }
  ]
},
fathom iron
#

yeah I think I'll just add all the amount_x fields to the python script

#

then you don't have to worry about computing any EVs

#

plus that's the only way it'll work for catalyst recipes

upbeat hatch
#

I mean, we can't really compute the EV, since they're a function of productivity

fathom iron
#

yeah

upbeat hatch
#

You could calculate it yourself, theoretically

fathom iron
#

yes that would be the plan, loop over all the prod/qual combinations, and calculate EV for each one

upbeat hatch
#
public float GetExpected(float productivity)
{
    float baseAmount;
    if (Probability is > 0)
        baseAmount = Probability.Value * (0.5f * (AmountMin ?? Amount!.Value) + (AmountMax ?? Amount!.Value));
    else
        baseAmount = Amount!.Value;

    if (IgnoredByProductivity != null)
        baseAmount += Math.Max(0, (baseAmount - IgnoredByProductivity.Value) * productivity);
    else
        baseAmount *= (1 + productivity);

    if (ExtraCountFraction != null)
        baseAmount += ExtraCountFraction.Value;

    return baseAmount;
}

You'd need to get the ignored_by_productivity and extra_count_fraction values though

#

baseAmount I can supply using the EV above, that's not a problem

fathom iron
#

I can update the python script to use those from the config file

upbeat hatch
#

^ file with those two fields present; amount is the expected value based on the min/max/prob

#

Hm, the additional_prod for the EMP seems wrong

upbeat hatch
#
{
  "key": "big-mining-drill#mining-tungsten-ore",
  "allow_productivity": true,
  "module_slots": 4,
  "additional_prod": 0,
  "ingredients": [
    {
      "name": "patch-tungsten-ore",
      "amount": 1
    }
  ],
  "results": [
    {
      "name": "tungsten-ore",
      "amount": 1
    }
  ]
},

Do you think this is a good idea

upbeat hatch
#

Huh, okay, so for some reason some items are... not there? It's "just" 257 items, which seems way too few

#

I'm not entirely sure what is missing, but rails would be definitely one of them

#

This looks better.

upbeat hatch
#

@fathom iron: I see you've changed the format a bit around? What are the crafting machines for?

#

oh, it's a n:m mapping between recipes and machines, I see

#

Still doesn't solve the productivity issues though, does it?

fathom iron
#

I haven't solved that part yet, no.

upbeat hatch
#

Updated JSON in the new format with recipes, crafting machines, and the recipeVars I think

fathom iron
#

I do plan to keep updating the config format, so apologies if it's not backwards-compatible

#

I'm trying to make it closer and closer to the factorio format

#

so eventually those fields could be passed in without changing anything

upbeat hatch
#

It's not a big deal

#

I'm using a JSON serializer and have the data structures as C# types

#

I can very easily shift it around

steel lagoon
#

what does it mean when the solves says the problem has no optimal solution...?

steel lagoon
#

apparently my problem is "infeasible" by LP standards

fathom iron
#

I made some more updates to the script if anyone's interested

shell meadow
#

No way to enter productivity research yet, is there? Also, it's adding legendary assembling+recycling of landfill or stone furnace just to sink the stone byproduct from molten iron and copper

fathom iron
distant igloo
#

That's typically easy and convenient in a linear solver, yeah

fathom iron
#

I added support for byproducts

fathom iron
#

I think there's a bug, I can't make legendary holmium plates from scrap while allowing byproducts, it just says that the problem does not have an optimal solution

#

but it works fine for epic holmium plates

#

or if byproducts are turned off

#

even weirder, it works if the module cost is set to 0.91, but fails at 0.92

fathom iron
#

adding a building cost seemed to help, I think it didn't like that recipes with zero modules could be added for free

distant igloo
#

huh, no optimal recipe chain is... surprising. if you only include the module cost, do you get the same error?

#

you could also try a constraint of "cost >= 0.01" and see what it spits out. that gives a hint to what the unbounded solutions look like

#

is it possible that you're allowing recycling into scrap?

#

other possibility: are you rewarding the setup for making modules?

fathom iron
#

I think infinities just don't mix well with zero-cost recipes. Even just setting the upper-bounds to a very large number like 999999 fixed it. I'm guessing there was probably some intermediate step where the solver wanted to set a couple variables to the max possible, even if it brought them back down again later.

upbeat hatch
#

I'm wondering about the implementation - wouldn't it be possible to model this as a (rather large) graph too, where each item is a node, and the edges are recipes (with different chances), then simply run some pathfinding/filling algorithm on it?

fathom iron
#

You're not really finding a "path" though, its a balancing act between all the possible recipes

#

You can represent the production chain as a graph though, and some tools print that out at the end

distant igloo
#

Some recipes involve three items (eg two inputs, one output), so it's not really a graph. It's kind of a multigraph, but multigraphs are terrible

fathom iron
#

If anyone else has written their own linear solver examples it might not be a bad idea to cross check results

distant igloo
#

it's tricky because there are so many different assumptions you can put in, and the chains you get are so complicated

#

here's a test case that's maybe easy to confirm: what do you get as the most ore-efficient way to make legendary iron plates from normal nauvis ores? (ignore oil and water costs, don't allow scrap or asteroids, no productivity research, but all buildings available.)

I get the following (picture because it's too long to send). Basically, cycle batteries. Make batteries in cryo plants with 8 prod modules (except that normal tier ingredients get 7 prod 1 qual instead). I get 4.6136 ore consumed per plate, but that's not including the 50% mining drain modifier of big drills. (it is including the prod bonus in those drills, though.)

(see what I said about lots of assumptions?)

#

it also makes sulfur with a little bit of prod and recycles legendary batteries with a little bit of quality, but those recipes are both really underconstrained, because the modules have no impact on the output at all

#

if you have a test case on your side I can try and get my side to do it too

shell meadow
#

Huh, with quality only coming from recycling but not the battery recipe? Fascinating

distant igloo
#

yeah, the more slots you get, the better prod is

#

8 slots is craaaaaaaaaaazy

fathom iron
#

I'm basically forcing the mining drills to use quality in my script, and also not accounting for resource drain, but I'm getting around 24 ores/plate. Though I am seeing the battery recipe in the outputs.

distant igloo
#

I'm not sure quality in miners is ever correct tbh. It costs a lot of modules AND it doesn't save ore consumption

#

I see the same module mix on the battery cryo plants too!

fathom iron
#

I guess the reason for me is I'm not sure how much one needs to worry about ore patches running out

shell meadow
#

if you're at a point of mathing out quality grinders, you are probably not too worried about finite ores

distant igloo
#

I suppose, but I'm not sure what other point there is in measuring ore cost

#

If you're not worried about that, you should measure buildings or modules or something

fathom iron
#

yeah I added that as options to the script

distant igloo
#

but measuring modules is haaaaaard. I don't want to input all the beacon arrangements that might matter...

fathom iron
#

I don't worry at all about beacons

shell meadow
#

oh!! I just realized that distinct recipe count would be a good regularization hyperparam

distant igloo
#

becaons definitely matter a lot for saving prod modules

fathom iron
#

usually it's just (num module slots) x (recipe var)

distant igloo
#

and they might matter for saving quality modules sometimes

fathom iron
#

yeah I've thought about adding beacons to the script

#

and maybe just not giving them a cost

distant igloo
#

do you have an understandable test case that goes from module cost?

#

(also are you fixing one tier of module when you do module cost? otherwise you need to decide the relative cost of different tiers, which seems tricky)

fathom iron
#

yeah I just always run the script with only one allowed prod module and one allowed quality module that you set in the beginning

distant igloo
#

I get that with 11.89 modules you can make 1 legendary iron plate per second. (imagine if you could have fractional buildings in real life...) you use express underground belts, but the exact mix of what things you recycle is kind of complicated.

fathom iron
# distant igloo do you have an understandable test case that goes from module cost?

I did make a test case with just two items, four module slots, t3 legendary modules:

python .\scripts\linear_solver.py --config .\examples\one_step_optimize_modules.json
Solving...

Solution:
Objective value = 539.3072768635545

Inputs used:
input__normal__item-1: 122.7832364500082

Buildings used: 218.60347845336278

Modules used: 539.3072768635545

Recipes used:
normal__craft-1-to-2__assembling-machine-3__3-qual__1-prod: 101.3363483499971
uncommon__craft-1-to-2__assembling-machine-3__2-qual__2-prod: 4.916175331737391
rare__craft-1-to-2__assembling-machine-3__2-qual__2-prod: 2.63497636827681
epic__craft-1-to-2__assembling-machine-3__2-qual__2-prod: 0.8371174698170993
legendary__craft-1-to-2__assembling-machine-3__0-qual__4-prod: 0.14686537324283389
normal__recycle-2-to-1__recycler__0-qual__0-prod: 83.77665923747415
uncommon__recycle-2-to-1__recycler__4-qual__0-prod: 19.067612656339616
rare__recycle-2-to-1__recycler__4-qual__0-prod: 4.5604476009472865
epic__recycle-2-to-1__recycler__4-qual__0-prod: 1.3272760655305031
distant igloo
#

If you allow recycling the ingredient into itself, you get a better result I think

#
{'solver': <sage.numerical.backends.glpk_backend.GLPKBackend object at 0x7ffa44ebd8e0>,
 'objective': -330.64804154944665,
 'rates': {"big-miner/mine-abstract/normal/('empty-slot', 'empty-slot', 'empty-slot')": 1219.281151007839,
  "assembler-3/abstract-recipe/legendary/('legendary/prod-3', 'legendary/prod-3', 'legendary/prod-3', 'legendary/prod-3')": 0.21055090519758612,
  "assembler-3/abstract-recipe/epic/('legendary/prod-3', 'legendary/quality-3', 'legendary/quality-3', 'legendary/quality-3')": 1.0828332267304426,
  "assembler-3/abstract-recipe/rare/('legendary/quality-3', 'legendary/quality-3', 'legendary/quality-3', 'legendary/quality-3')": 9.474790733891378,
  "recycler/recycle-abstract-two/rare/('legendary/quality-3', 'legendary/quality-3', 'legendary/quality-3', 'legendary/quality-3')": 0.683278177924859,
  "recycler/recycle-abstract-two/epic/('legendary/quality-3', 'legendary/quality-3', 'legendary/quality-3', 'legendary/quality-3')": 0.34481458049445207,
  "recycler/recycle-abstract-one/normal/('empty-slot', 'empty-slot', 'empty-slot', 'legendary/quality-3')": 261.9293557481932,
  "recycler/recycle-abstract-one/uncommon/('legendary/quality-3', 'legendary/quality-3', 'legendary/quality-3', 'legendary/quality-3')": 5.383403826074644}}
#

though I suppose that depends on the self-recycling speed...

#

Are you allowing buildings with empty slots?

#

I think they're actually correct sometimes

#
In [178]: quality.do_lp({"legendary/abstract-two": 1.0})
Out[178]: 
{'solver': <sage.numerical.backends.glpk_backend.GLPKBackend object at 0x7ffa44211220>,
 'objective': -300.8081003820032,
 'rates': {"assembler-3/abstract-one/normal/('empty-slot', 'empty-slot', 'empty-slot', 'empty-slot')": 769637.5301016847,
  "assembler-3/abstract-two/normal/('empty-slot', 'empty-slot', 'empty-slot', 'empty-slot')": 1005.2408556430165,
  "assembler-3/abstract-two/legendary/('legendary/prod-3', 'legendary/prod-3', 'legendary/prod-3', 'legendary/prod-3')": 0.587843251204259,
  "assembler-3/abstract-two/rare/('legendary/prod-3', 'legendary/prod-3', 'legendary/quality-3', 'legendary/quality-3')": 6.193382191149627,
  "assembler-3/abstract-two/epic/('legendary/prod-3', 'legendary/prod-3', 'legendary/quality-3', 'legendary/quality-3')": 1.94601208744113,
  "assembler-3/abstract-two/uncommon/('legendary/quality-3', 'legendary/quality-3', 'legendary/quality-3', 'legendary/quality-3')": 20.561744774516228,
  "recycler/recycle-abstract-two/normal/('empty-slot', 'empty-slot', 'empty-slot', 'legendary/quality-3')": 165.33566704654882,
  "recycler/recycle-abstract-two/uncommon/('legendary/quality-3', 'legendary/quality-3', 'legendary/quality-3', 'legendary/quality-3')": 2.409579465763625,
  "recycler/recycle-abstract-two/rare/('legendary/quality-3', 'legendary/quality-3', 'legendary/quality-3', 'legendary/quality-3')": 1.6754692451061044,
  "recycler/recycle-abstract-two/epic/('legendary/quality-3', 'legendary/quality-3', 'legendary/quality-3', 'legendary/quality-3')": 0.49407731868263294}}
#

[I added a suuuuper slow recipe that makes abstract-one so that recycling it would be super slow]

fathom iron
#

I'm not checking all possibilities with empty slots, but I am looping the quality modules from 0 to slots, and if the recipe allows prod then it always fills the remaining with prod

#

my solver doesn't have any hard-coded knowledge about recycling, instead the recycling and crafting recipes are all lumped together as "recipes"

distant igloo
#

what speed are your recipe and recyling recipe in this case?

fathom iron
#

the recipes themselves have "energy_required" fields of 1 and 0.25 for crafting and recycling respectively (this is how factorio represents data, and is the number of seconds basically)

distant igloo
#

I believe recyling recipes are usually sixteen times faster, not 4 times faster

fathom iron
#

and the crafting machine/recycler have factorio stats too, so 1.25 and 0.5 respectively

distant igloo
#

yeah, the pipe recipe has energy 0.5 and the recyling has energy 0.03125, so 16 times less

fathom iron
#

hmm, iron gear wheels are 0.5 and 0.0625

distant igloo
#

are you on the latest version?

fathom iron
#

in the factorio data file it says pipe recycling is 0.0625

#

no

distant igloo
#

they fixed a bug where default-speed recipes had the wrong recyling speed

fathom iron
#

did they change it?

distant igloo
#

basically the quality lua code interpreted "default speed" as 1, but the engine uses 0.5. so that caused a factor of 2 difference for any default-speed recipe

#

oh no, I have bad news. if I let my solver use speed modules, even without beacons, it likes them 😦

#
In [185]: quality.do_lp({"legendary/abstract-two": 1.0})
Out[185]: 
{'solver': <sage.numerical.backends.glpk_backend.GLPKBackend object at 0x7ffa44e86700>,
 'objective': -225.1630418617982,
 'rates': {"assembler-3/abstract-one/normal/('empty-slot', 'empty-slot', 'empty-slot', 'empty-slot')": 359614.3449373728,
  "assembler-3/abstract-two/normal/('empty-slot', 'empty-slot', 'empty-slot', 'empty-slot')": 454.84818331999674,
  "assembler-3/abstract-two/legendary/('legendary/prod-3', 'legendary/prod-3', 'legendary/prod-3', 'legendary/prod-3')": 0.5823369608363039,
  "assembler-3/abstract-two/epic/('legendary/prod-3', 'legendary/prod-3', 'legendary/quality-3', 'legendary/quality-3')": 1.8787352305817517,
  "assembler-3/abstract-two/rare/('legendary/prod-3', 'legendary/quality-3', 'legendary/quality-3', 'legendary/quality-3')": 5.529242886969374,
  "assembler-3/abstract-two/uncommon/('legendary/quality-3', 'legendary/quality-3', 'legendary/quality-3', 'legendary/speed-3')": 9.394454732943137,
  "recycler/recycle-abstract-two/uncommon/('legendary/quality-3', 'legendary/quality-3', 'legendary/quality-3', 'legendary/quality-3')": 3.227050246399163,
  "recycler/recycle-abstract-two/rare/('legendary/quality-3', 'legendary/quality-3', 'legendary/quality-3', 'legendary/quality-3')": 1.3312925829706916,
  "recycler/recycle-abstract-two/epic/('legendary/quality-3', 'legendary/quality-3', 'legendary/quality-3', 'legendary/quality-3')": 0.5047770420112728,
  "recycler/recycle-abstract-two/normal/('legendary/quality-3', 'legendary/quality-3', 'legendary/quality-3', 'legendary/speed-3')": 33.842870782737855}}
fathom iron
distant igloo
#

there's a mod that has a command to dump a json file, but I'm not sure it's updated for 2.0

#

but if you fix the abstract recipe you're using, we can at least compare those results

fathom iron
#

this is with the recycler energy set to 0.0625:

python .\scripts\linear_solver.py --config .\examples\one_step_optimize_modules.json
Solving...

Solution:
Objective value = 3442.3444906506215

Inputs used:
input__normal__item-1: 1105.448118428236

Buildings used: 1461.1766572200288

Modules used: 3442.3444906506215

Recipes used:
normal__craft-1-to-2__assembling-machine-3__3-qual__1-prod: 726.4750370756356
uncommon__craft-1-to-2__assembling-machine-3__4-qual__0-prod: 8.023681051538485
rare__craft-1-to-2__assembling-machine-3__3-qual__1-prod: 3.140666188774729
epic__craft-1-to-2__assembling-machine-3__4-qual__0-prod: 0.6846364967148661
legendary__craft-1-to-2__assembling-machine-3__0-qual__4-prod: 0.08058437133014072
normal__recycle-2-to-1__recycler__0-qual__0-prod: 600.5905345573731
uncommon__recycle-2-to-1__recycler__4-qual__0-prod: 106.69788632365011
rare__recycle-2-to-1__recycler__4-qual__0-prod: 13.575685484424904
epic__recycle-2-to-1__recycler__4-qual__0-prod: 1.9079456705866382
#

no wait that's completely wrong

#

disregard that

distant igloo
#

I was gonna say, that number sounds pretty high

fathom iron
#

I changed the output instead of the energy...

#

maybe this?

python .\scripts\linear_solver.py --config .\examples\one_step_optimize_modules.json
Solving...

Solution:
Objective value = 367.64283330973575

Inputs used:
input__normal__item-1: 84.15177514007344

Buildings used: 91.91070832743394

Modules used: 367.64283330973575

Recipes used:
normal__craft-1-to-2__assembling-machine-3__3-qual__1-prod: 64.03495415971946
uncommon__craft-1-to-2__assembling-machine-3__2-qual__2-prod: 7.590132010447865
rare__craft-1-to-2__assembling-machine-3__2-qual__2-prod: 2.7374027764924347
epic__craft-1-to-2__assembling-machine-3__2-qual__2-prod: 0.8410756914115006
legendary__craft-1-to-2__assembling-machine-3__0-qual__4-prod: 0.14705707906456278
normal__recycle-2-to-1__recycler__4-qual__0-prod: 11.028936929006369
uncommon__recycle-2-to-1__recycler__4-qual__0-prod: 4.086186881734061
rare__recycle-2-to-1__recycler__4-qual__0-prod: 1.1141224382986739
epic__recycle-2-to-1__recycler__4-qual__0-prod: 0.33084036125900995
distant igloo
#

hm. using the same rules as you, I'm getting a worse result, and your result SHOULD be viable in my solver. odd.

#

wait, here's a really dumb question: are you trying to make item 1 here or item 2?

#

and you're making one per second, right?

#

given that you're not recyling legendaries, looks like you're making item 2

distant igloo
#

.... This is a wild hunch, but I think you're turning speed penalties into speed bonuses. If I constrain my solver to use exactly your recipes it uses exactly 13/7 times as much of the normal forward recipe, and notably that assembler should be at a 30% speed penalty

fathom iron
#

new result:

python .\scripts\linear_solver.py --config .\examples\one_step_optimize_modules.json
Solving...

Solution:
Objective value = 621.1603493504524

Inputs used:
input__normal__item-1: 96.31209734078664

Buildings used: 155.29008733761316

Modules used: 621.1603493504526

Recipes used:
normal__craft-1-to-2__assembling-machine-3__4-qual__0-prod: 112.1702833146833
uncommon__craft-1-to-2__assembling-machine-3__3-qual__1-prod: 13.303287769657612
rare__craft-1-to-2__assembling-machine-3__2-qual__2-prod: 6.121944220734775
epic__craft-1-to-2__assembling-machine-3__2-qual__2-prod: 1.952256431966584
legendary__craft-1-to-2__assembling-machine-3__0-qual__4-prod: 0.5873769995429726
normal__recycle-2-to-1__recycler__4-qual__0-prod: 13.180008289475289
uncommon__recycle-2-to-1__recycler__4-qual__0-prod: 5.76257666066572
rare__recycle-2-to-1__recycler__4-qual__0-prod: 1.71446337471775
epic__recycle-2-to-1__recycler__4-qual__0-prod: 0.49789027616910436
distant igloo
#

I get the same result using your constraints 🙂

In [258]: quality.do_lp({"legendary/abstract-two": 1.0})
Out[258]: 
{'solver': <sage.numerical.backends.glpk_backend.GLPKBackend object at 0x7ffa3f191e80>,
 'objective': -621.1603493504472,
 'rates': {"assembler-3/abstract-one/normal/('empty-slot', 'empty-slot', 'empty-slot', 'empty-slot')": 77049.67787262842,
  "assembler-3/abstract-two/legendary/('legendary/prod-3', 'legendary/prod-3', 'legendary/prod-3', 'legendary/prod-3')": 0.587376999542973,
  "assembler-3/abstract-two/rare/('legendary/prod-3', 'legendary/prod-3', 'legendary/quality-3', 'legendary/quality-3')": 6.12194422073478,
  "assembler-3/abstract-two/epic/('legendary/prod-3', 'legendary/prod-3', 'legendary/quality-3', 'legendary/quality-3')": 1.9522564319665852,
  "assembler-3/abstract-two/uncommon/('legendary/prod-3', 'legendary/quality-3', 'legendary/quality-3', 'legendary/quality-3')": 13.303287769657604,
  "assembler-3/abstract-two/normal/('legendary/quality-3', 'legendary/quality-3', 'legendary/quality-3', 'legendary/quality-3')": 112.17028331468207,
  "recycler/recycle-abstract-two/normal/('legendary/quality-3', 'legendary/quality-3', 'legendary/quality-3', 'legendary/quality-3')": 13.180008289475186,
  "recycler/recycle-abstract-two/uncommon/('legendary/quality-3', 'legendary/quality-3', 'legendary/quality-3', 'legendary/quality-3')": 5.762576660665746,
  "recycler/recycle-abstract-two/rare/('legendary/quality-3', 'legendary/quality-3', 'legendary/quality-3', 'legendary/quality-3')": 1.7144633747177505,
  "recycler/recycle-abstract-two/epic/('legendary/quality-3', 'legendary/quality-3', 'legendary/quality-3', 'legendary/quality-3')": 0.4978902761691046}}
#

But you can actually do a lot better with empty slots:

In [260]: quality.do_lp({"legendary/abstract-two": 1.0})
Out[260]: 
{'solver': <sage.numerical.backends.glpk_backend.GLPKBackend object at 0x7ffa3f35bd00>,
 'objective': -305.870123189209,
 'rates': {"assembler-3/abstract-one/normal/('empty-slot', 'empty-slot', 'empty-slot', 'empty-slot')": 785365.8969385906,
  "assembler-3/abstract-two/normal/('empty-slot', 'empty-slot', 'empty-slot', 'empty-slot')": 1025.951530945252,
  "assembler-3/abstract-two/legendary/('legendary/prod-3', 'legendary/prod-3', 'legendary/prod-3', 'legendary/prod-3')": 0.5878336863294126,
  "assembler-3/abstract-two/rare/('legendary/prod-3', 'legendary/prod-3', 'legendary/quality-3', 'legendary/quality-3')": 6.264279278493663,
  "assembler-3/abstract-two/epic/('legendary/prod-3', 'legendary/prod-3', 'legendary/quality-3', 'legendary/quality-3')": 1.9577569050289174,
  "assembler-3/abstract-two/uncommon/('legendary/quality-3', 'legendary/quality-3', 'legendary/quality-3', 'legendary/quality-3')": 20.835697372607637,
  "recycler/recycle-abstract-two/normal/('empty-slot', 'empty-slot', 'empty-slot', 'legendary/quality-3')": 168.74202811599542,
  "recycler/recycle-abstract-two/uncommon/('legendary/quality-3', 'legendary/quality-3', 'legendary/quality-3', 'legendary/quality-3')": 2.4481944412813985,
  "recycler/recycle-abstract-two/rare/('legendary/quality-3', 'legendary/quality-3', 'legendary/quality-3', 'legendary/quality-3')": 1.6912460753939889,
  "recycler/recycle-abstract-two/epic/('legendary/quality-3', 'legendary/quality-3', 'legendary/quality-3', 'legendary/quality-3')": 0.4970160091683563}}
#

most of the savings are from skipping all modules in abstract-two/normal; the gain from dropping down to only one module in recycle-abstract-two/normal is relatively minor

#

if you allow speed modules, then you no longer have empty slots, which kinda makes sense to me:

In [266]: quality.do_lp({"legendary/abstract-two": 1.0})
Out[266]: 
{'solver': <sage.numerical.backends.glpk_backend.GLPKBackend object at 0x7ffa44df9040>,
 'objective': -229.19510821006196,
 'rates': {"assembler-3/abstract-one/normal/('empty-slot', 'empty-slot', 'empty-slot', 'empty-slot')": 367354.53204708843,
  "assembler-3/abstract-two/normal/('empty-slot', 'empty-slot', 'empty-slot', 'empty-slot')": 464.85862960719913,
  "assembler-3/abstract-two/legendary/('legendary/prod-3', 'legendary/prod-3', 'legendary/prod-3', 'legendary/prod-3')": 0.5822736182767487,
  "assembler-3/abstract-two/epic/('legendary/prod-3', 'legendary/prod-3', 'legendary/quality-3', 'legendary/quality-3')": 1.890789772507216,
  "assembler-3/abstract-two/rare/('legendary/prod-3', 'legendary/quality-3', 'legendary/quality-3', 'legendary/quality-3')": 5.590178851978394,
  "assembler-3/abstract-two/uncommon/('legendary/quality-3', 'legendary/quality-3', 'legendary/quality-3', 'legendary/speed-3')": 9.520498654494972,
  "recycler/recycle-abstract-two/uncommon/('legendary/quality-3', 'legendary/quality-3', 'legendary/quality-3', 'legendary/quality-3')": 3.2762044100302177,
  "recycler/recycle-abstract-two/rare/('legendary/quality-3', 'legendary/quality-3', 'legendary/quality-3', 'legendary/quality-3')": 1.343476059159743,
  "recycler/recycle-abstract-two/epic/('legendary/quality-3', 'legendary/quality-3', 'legendary/quality-3', 'legendary/quality-3')": 0.5076600307706743,
  "recycler/recycle-abstract-two/normal/('legendary/quality-3', 'legendary/quality-3', 'legendary/quality-3', 'legendary/speed-3')": 34.58769565529752}}
#

I added some very rough beacon support, but I think it suggests that the standard "8-beacon" setup is good. (I didn't code in the fact that different buildings are different sizes; everything just assumes 3x3, which is explicitly wrong for recyclers...)

[WRONG]
#

the setups I encoded were 0, 1 (with 8 buildings around it), 4 (rows of buildings with beacons on one side), 8 (rows of buildings with beacons on both sides), and 12

#

oh crap wait no I forgot about the quality penalty

#
In [272]: quality.do_lp({"legendary/abstract-two": 1.0})
Out[272]: 
{'solver': <sage.numerical.backends.glpk_backend.GLPKBackend object at 0x7ffa32dbc700>,
 'objective': -115.74848976953588,
 'rates': {"assembler-3/bcn-0/abstract-one/normal/('empty-slot', 'empty-slot', 'empty-slot', 'empty-slot')": 369605.3827047863,
  "assembler-3/bcn-0/abstract-two/normal/('empty-slot', 'empty-slot', 'empty-slot', 'empty-slot')": 465.9380809389043,
  "assembler-3/bcn-8/abstract-two/rare/('legendary/prod-3', 'legendary/prod-3', 'legendary/prod-3', 'legendary/prod-3')": 0.4598488632042923,
  "assembler-3/bcn-8/abstract-two/legendary/('legendary/prod-3', 'legendary/prod-3', 'legendary/prod-3', 'legendary/prod-3')": 0.022607026031969703,
  "assembler-3/bcn-0/abstract-two/epic/('legendary/prod-3', 'legendary/prod-3', 'legendary/quality-3', 'legendary/quality-3')": 2.3700651518899787,
  "assembler-3/bcn-1/abstract-two/uncommon/('legendary/quality-3', 'legendary/quality-3', 'legendary/quality-3', 'legendary/quality-3')": 4.808189790193099,
  "recycler/bcn-1/recycle-abstract-two/normal/('legendary/quality-3', 'legendary/quality-3', 'legendary/quality-3', 'legendary/quality-3')": 16.00062091136345,
  "recycler/bcn-1/recycle-abstract-two/uncommon/('legendary/quality-3', 'legendary/quality-3', 'legendary/quality-3', 'legendary/quality-3')": 0.6213082744515136,
  "recycler/bcn-0/recycle-abstract-two/rare/('legendary/quality-3', 'legendary/quality-3', 'legendary/quality-3', 'legendary/quality-3')": 2.6423899432342353,
  "recycler/bcn-0/recycle-abstract-two/epic/('legendary/quality-3', 'legendary/quality-3', 'legendary/quality-3', 'legendary/quality-3')": 0.4314821013967977}}

So beacons with quality only make sense with particularly cheap inputs, but they ARE good when you want a ton of throughput of those items at low cost

#

beacons with prod are of course amazing

#

legendary beacons don't change the recipes used and they only make the setup marginally cheaper

fathom iron
#

I'm guessing the best way to add speed modules to my script is probably with beacons only. First because it's probably optimal, since it doesn't take up any slots that could be used for prod/qual. Second because the combinatorics get pretty bad when you start checking every combination of module slots. Since I'm only checking prod/qual there's only O(N) variants of each recipe where N is the number of module slots. If I check speed beacons it's more like O(N^2), one linear term from module slots and another linear term from checking each possible of speed beacon bonus.

#

I should go check the math on beacons though, I remember they changed it a bunch and there's some diminishing effect formula.

#

Wonder if I should just have 2 modules / beacon always, or maybe check 1 module/1 beacon, 2 modules / 1 beacon, 3 modules / 2 beacons, etc.

hazy fractal
#

can you do a two-phase solve if building/module costs are 0? find the optimal pipeline, then optimize the building & beacon counts?

hazy fractal
#

calculator could definitely use an output total-- I think this means ~1.8 output?

epic__productivity-module__electromagnetic-plant__5-qual__0-prod__0-beaconed-speed: 4.768079627580483
legendary__productivity-module__electromagnetic-plant__0-qual__0-prod__0-beaconed-speed: 0.6697057839050451
upbeat hatch
#

It's what I'm using so far, and the fact that it's vanilla sounds pretty promising to me, as it's unlikely to break

upbeat hatch
#

Hm. Where/How does it actually define what quality does to modules?

#

Oh, it's just hardcoded based on the tier, OK

upbeat hatch
#

So the recipe has a chance of giving sum(higher_or_equal_quality, quality => chance^(quality.tier - ingredients.tier) * expected_items) in total, except this has to be normalized because it can't give all of those

#

So I guess it's smarter to start with the highest quality, and then for each following tier, subtract the items from higher tiers

#

So if we expect it to give 50 items in total, and 0.1 legendary, 0.5 epic, 1 rare, 5 uncommon; then the it would in total give 0.1 legendary, 0.4 epic, 0.4 rare, 3.4 uncommon, and 45.7 common or something?

#

Hm, no.

0.1 legendary
0.5-0.1 = 0.4 epic
1-0.1-0.4 = 0.5 rare
5-0.1-0.4-0.5 = 4 uncommon
50-0.1-0.4-0.5-4 = 45 common

hazy fractal
upbeat hatch
#

Hm

#

I mean, I made up the numbers

#

But yeah, using q^(i-1)*(1-q) makes more sense than adding

distant igloo
#

One thing you can do: only include the recipes that you suspect are useful in the LP, but then output the implied prices (from the dual model) and check that the recipes you skipped are negative value

hazy fractal
#

testing summaries

fathom iron
#

that's a MUCH better output!!! If you make a PR I'll happily merge

hazy fractal
#

I'm not sure how to interpret the solution values so I left them out

fathom iron
#

the solution values should just be a literal building count

hazy fractal
#

# solved result is equivalent to number of buildings in units where craft_time=1 and craft_speed=1

fathom iron
#

but it tries to solve 1 output/sec which I guess results in small numbers

hazy fractal
#

does it have proper craft times yet?

fathom iron
#

that comment is out-dated, I've started incorporating factors such as the recipe energy and building crafting speed

#

I think it should

hazy fractal
#

so rounding up for building counts should work

fathom iron
#

but again a lot of that stuff hasn't been rigorously cross-checked with other solvers, so there could easily be bugs

hazy fractal
#

would still love to see outputs in items/m or whatever

upbeat hatch
#

I'm currently trying to set it up using the Google library thingy for C# I found, but I'm still a bit at a loss as to what is what

#

I guess items are variables, recipes are constraints, ingredients are negatively bound variables on them, and products are positive bound ones?

#

(and you want to, uh... minimize constraints?)

fathom iron
upbeat hatch
#

it wasn't as bad as analysis because it seemed to deal with a finite-ish realm of things, rather than making up stuff as you go, but it was still rather bizarre

#

It's a world I definitely do not get along

fathom iron
upbeat hatch
#

I suppose maximizing for the target item variable then would make sense?

fathom iron
upbeat hatch
#

Hm, let's see - if I can create variables (with a lower/upper bound), and constraints, and constraints can have coefficients with are other variables and a value, then.. uh.

#

Giving it a final constraint of the target makes sense. I'm just not entirely sure how I'll piece the rest together

upbeat hatch
#

Okay, I've skimmed through the document and what you've said, but I'm not quite sure it makes sense

#

If the recipes are variables, and you're trying to minimize the cost... the result of recipes isn't unique, though, is it? With recyclers at least, two recipes can have the same result - making it really difficult/impossible to optimize for?

fathom iron
#

yeah you could imagine a simple case where you can turn iron ore into iron plates using either furnaces or foundries. We know foundries should be better because of the prod bonus (ignoring calcite for now). Linear solvers can figure that out magically, and pick out foundries as "optimal" since they require less iron ore for the same iron plates.

distant igloo
#

Usually "ties" aren't too much of an issue; the solver will pick one somehow

upbeat hatch
#

Right, but I'm not quite sure how that would work

#

Like, what do you at the end optimize for?

#

x*foundryPlates + y*furnacePlates = 1?

#

minimize for x/y?

#

(I don't think I had this in linear algebra, but I do remember optimization like that being part of HS maths)

fathom iron
#

you'd have variables like numberOfFoundryRecipes , numberOfFurnaceRecipes, ironInputPerSecond, and a constraint on iron where ironInputPerSecond = numberOfFoundryRecipes + numberOfFurnaceRecipes

upbeat hatch
#

Right, I got that so far, minus the ironInputPerSecond

#

What are the relations between iron plates and iron ore? I assume those are constraints, too?

#

Is it a literal numberOfFoundryRecipes = ironOre / 1.5, numberOfFurnaceRecipes = ironOre?

#

(i.e. two constraints that link the variables together?)

#

This is where I struggle a bit if recipes are variables - because it means "ironOre" itself could not really exist, but rather, you would have to define (again) every possible producer of iron ore?

fathom iron
#

usually most items don't have associated variables. The exception is items that are inputs or byproducts to the system. For these we can construct a fake "recipe" variable that produces the item out of nothing, or voids the item.

upbeat hatch
#

Right, that makes sense.

fathom iron
#

this one is a matrix solver, which is a bit easier to grasp, since it can be solved with regular matrix algebra

#

linear solvers are similar, except they have too many columns and don't have a unique solution, but by having a cost function it's possible to still find an optimal solution. The behind-the-scenes math is way more complex, but you can import other solvers to do it for you and treat it like a black box.

upbeat hatch
#

Yes, Gauss flashbacks right there

hazy fractal
#

neither helmod nor factoryplanner have linear solvers, right?

upbeat hatch
#

I mean, at this point, I'm almost tempted to say that each recipe is a constraint and a variable in the form of recipeNum * sum(ingredients->amount) = recipeNum * sum(results->expectedAmount)- with recipeNum being if/how much the recipe is utilized, and the ingredients/results being variables that are utilized in the whole process, too

fathom iron
#

I think helmod actually is, factory planner is not (just a regular matrix solver) - side note I actually wrote the FP matrix solver

hazy fractal
#

nah looks like a matrix too

fathom iron
#

but I thought it did simplex

hazy fractal
#

oh, no, that's correct

distant igloo
#

Helmod routinely gives weird negative numbers IME

#

Maybe it's been updated since I used it, though

hazy fractal
#

it's really hard to use linear solvers without having to learn an uncomfortable amount about their guts

distant igloo
#

BTW, there's a good intro to LP on Kirk McDonald 's factorio calculator website

fathom iron
fathom iron
#

Though there was no shortage of people confused about selecting free items haha

distant igloo
#

Yuuuup

hazy fractal
#

wow, the impact of high tier quality modules is absurd

#

10x less iron required for legendary plates going from normal Q3s to legendary Q3s

upbeat hatch
#

It successfully found the best way to make legendary iron plates is by taking legendary iron ore and turn it into iron plates

#

... which is true, I guess.

#

I'm only running two recipes so far (iron-plate and iron-plate-recycling), but with all possible module combinations, and in all possible crafting places (for those recipes)

#

And yeah, for each item (... in each quality), there's a constraint that adds up the variables depending on whether they're ingredients (subtracted) or results (added)

upbeat hatch
#

I think I've set up the solver correctly - I just need to be able to tell it to not start with a simple recycler recipe from the get-go, but actually work its way up somehow

#

(Assuming I'm telling it to use normal ore, rather than legendary ore from the get-go, it will properly do normal->normal and normal->uncommon using a furnace; but for normal->legendary fall back to just recycling epic plates that it gets out of thin air I guess)

#

Aah, setting the bounds on inputs freely seems to... do the trick?

iron-plate @ electric-furnace (normal->normal) using [legendary-productivity-module-3+legendary-productivity-module-3]: 1820.4444444444441
iron-plate-recycling @ recycler (normal->legendary) using [legendary-quality-module-3+legendary-quality-module-3+legendary-quality-module-3+legendary-quality-module-3]: 2730.6666666666665

I'll need to counter-check that with your solver to be sure

upbeat hatch
#

OK, I think part of the reason why it's doing what it is doing is because the recycler recipes are borked. amount: 0.5, extra_count_fraction: 0.5 has an expected value of 1, which means it can basically endless recycle the same thing to get components to make more using productivity

distant pier
#

Is the optimal ratio of prod to quality universal, or situational for like every recipe?

hazy fractal
#

situational, it's usually mostly quality though

wild marlin
#

I remember that most reddit posts with math claimed that 2P2Q works best (assuming both legendary)

#

With base productivity 50% and more module slots it can change though, like 4P1Q

distant pier
#

When I'll gethome I'll try to make a program which takes desired ammount of legendaries/m and putputs a table of different modules combos and other stats

#

I have most of the math in exel table already

wild marlin
#

I think people above already kind of did those math

distant pier
#

Nice do they have a script which does what i wanna do?

distant pier
distant pier
wild marlin
#

By the way, what does LP mean?

hazy fractal
#

linear programming, the method of optimization that many factory planning tools use

fathom iron
#

Thinking it might be interesting to play around with a fake module 3 recipe that only uses module 2/red chips/blue chips (no special planet ingredients) to get a sense of which planet makes the most sense for doing quality stuff.

wild marlin
#

So I've been using scottmsul's program and was really surprised to see the actual best solution is quite far away from a normal expectation

#

I rembmer when it had fewer features (the legacy one) and it's really changed a lot

fathom iron
#

I think it's getting to a point where it has most of the needed features

#

The only major one left is the infinite prod research bonuses

wild marlin
#

maybe is there a way to add some 'cost' for having many different recipes?

#

the number of machines don't seem to represent that

fathom iron
#

I've thought about it but I'm not sure an LP can do that, as it would be non-linear

#

I think a better strategy is to re-run for different simple subsets of recipes using the allowed recipes feature

wild marlin
#

btw I'm the one who opened the second issue

#

if you remember

#

So for me, I just wanted to see how I can make a legendary quality module before I already have enough of them

#

And I was surprised when the solver said 'Hey please breed biters and fish'

#

I disallowed biochambers and it began to make more sense but the results were still a bit too complicated to set up

#

also when I run "python ./scripts/factorio_solver.py -oi quality-module-3 -q normal -ii scrap-resource=0.1 heavy-oil=0.1 -dc biochamber", your program outputs "... legendary 1Q4P" for copper cable but does this make sense?

#

I guess the solution doesn't need more than 4 prod modules for legendary copper cable

fathom iron
#

I'm guessing maybe it's over-producing copper and by skipping out on a prod module maybe it has to recycle the legendary copper less

#

are you allowing byproducts? That might help

#

over-producing copper relative to iron or other inputs, that is

wild marlin
#

I guess I am, isn't the program allowing byproducts by default?

wild marlin
fathom iron
#

try adding the flag "--allow-byproducts"

#

I just realized the short version is "-av" I think it was meant to be "-ab"

wild marlin
#

much simpler

#

yeah and I see how it's different

#

This is closer to what I'd have expected before

#

Still some surprise remaining though, like making beacon in the middle

fathom iron
#

might be worth playing around with the cost functions for buildings/modules/beacons

#

I just set a bunch of things to 1 by default which might not be optimal

hazy fractal
distant pier
#

I just copy paste huge factories making legendary modules only and they work for free basically

fathom iron
# distant pier Dude it's vulcanus

that wouldn't surprise me. I'm still not actually that far into space age yet, probably spent more time on the solver than actually playing 🤣. Finished vulcanus and fulgora, making my way through gleba currently.

distant pier
#

Fulgora will kill you ups i am guessing if you attrmpt to expand to much there

distant pier
#

I sat with exel calculator all day yesterday lol

#

Comparing results to ingame results

fathom iron
#

someone found a calculation bug in my code today, was a pretty simple one line fix though. But I still feel like I'm not 100% sure it's perfectly accurate.

distant pier
#

Justbuilt an ingame factory and compre results

fathom iron
#

I think I'd rather compare with other solvers

distant pier
#

You can increadd the game speed 60 timrs

distant pier
#

I can give you mine

fathom iron
distant pier
#

Yeah

fathom iron
#

yeah that was one of the first things I did, I still have the original code for that

#

but the latest script runs on every recipe in the game

#

and tries to get accurate building counts and throughputs from ores-to-modules

distant pier
#

That's advanced..

fathom iron
#

and a lot of the results it gives are extremely complex and hard to interpret...

sullen bluff
#

in mine you input the prod and quality bonuses for machines and recyclers, some other stuff and input resources/m and it gives number of machines, recyclers, modules that you need

#

and legendaries/m, ration of legendaries to common input

#

very simple but effective, enough to build any factory basically

#

numbers corelate to the game btw

#

also this

fathom iron
#

the tricky part though is when there's multiple stages of production, it's usually more optimal to "spread out" the quality bumps, rather than going straight from normal to legendary in one shot

sullen bluff
#

true

#

but on vulcanus everything is free

#

so not always

#

like for cicruits it doesn't matter does it

#

only constraint is plastic but you have so much coal that again not really

#

btw if you have some numbers you would want to comare i'll gladly do so

fathom iron
#

probably the main number if you want to check for correctness is 79.9 normal inputs per legendary output, assuming four module slots. 2 qual / 2 prod at every quality step, except the last which is legendary. This is a number that's been verified several times now by multiple people.

sullen bluff
#

give me a sec, ok

fathom iron
#

yeah, that's all t3 legendary modules

#

a bunch of us calculated it when they first announced quality in the FFF

sullen bluff
fathom iron
#

yes

#

but the 2/2 split everywhere else was calculated to be optimal, at least in terms of inputs / output

sullen bluff
#

i am not sure how productivity in recycklers works

#

by default they spit 0,25 of input

#

if they have 4 leg prod modules will they spit 0,5?

sullen bluff
#

you typed 79,9, not 76,6?

#

i got 76,6

#

btw when you use prod the ammount of crafters you need grows very fast

#

for 2 qual 2 prod you need like 2 more times crafters to consume the same input than 4 qual

#

which matters if you wenna do circuits on vulcanus let's say

sullen bluff
#

lmao factorio makes you have fun staring at exel

#

i got some insane results for a legendary green circuit factory gotta build it rn

fathom iron
#

It's 79.9

main tartan
#

I guess 2/2 is optimal, but using 4 prod and being able to apply speed beacons is considerably more pleasant XD

upbeat hatch
distant pier
fathom iron
distant igloo
#

But also that person was talking about speed+prod, not speed+qual

#

Speed+prod is still fine

sullen bluff
#

btw the more i tried to design a legendary circuit factory recycling everything else the more i think it's better to make a lot of common ingredients and grind only at final stage

fathom iron
hazy fractal
main tartan
#

@fathom iron I asked your solver how to make prod 3 modules and it's doing something with underground belts?!

#

lol

#

python3 ./scripts/factorio_solver.py --input-items electronic-circuit=1 advanced-circuit=1 biter-egg=1 --output-item productivity-module-3 --output-amount 1

main tartan
#

is it supposed to do stuff like "Electronic circuit in Electromagnetic plant: normal 4Q1P" even though I specified that as an input item

#

I guess I don't understand how iron gear wheels, copper cables etc are even getting involved when I specified red & green circuits as fixed inputs

hazy fractal
#

it has to recycle them sometimes

distant igloo
#

You have normal green circuits as an input, but not higher tier ones, and it wants to make them by crafting them apparently

hazy fractal
#

yeah, it also needs to make processing units

distant igloo
fathom iron
# main tartan I guess I don't understand how iron gear wheels, copper cables etc are even gett...

To elaborate, my guess is it has to do with the difference between upping one quality step vs jumping multiple quality steps in a single production step (i.e. 24.8% vs 10% for a fully-loaded assembler 3). This asymmetry probably favors adding extra stages of production, so for instance making underground belts just to recycle them is better for making legendary, than just recycling iron plates.

main tartan
#

Maybe like a “recipe weight” feature would be cool to find sequences that don’t use so many steps

distant igloo
#

Difficult to do, algorithmically.

shell meadow
#

Is there a way to specify liquid input resources? Getting KeyError: 'normal__lava-resource'

fathom iron
#

the resource logic is mainly needed to get accurate quality counts when quality modules are placed in miners

fathom iron
#

I added productivity research to the script, I know a few users were interested in having that

sullen bluff
upbeat hatch
#

I've realized why my script was doing really weird things - I've had the wrong constraints (a common recipe never generated uncommon results, but rather had a separate constraint, which obviously could be set to zero for "nicer" results). Now I have more convoluted and a bit weird things - like making epic electronic circuits apparently involves... solar panels?

#

I feel like part of it is that it's now assuming that the recipes can be happening simultaneously - i.e. having one furnace with quality, and another with productivity, seems to be OK. Which is... questionable

upbeat hatch
#

Can I solve this problem somehow with another constraint, or do I have to do some additional refining step (i.e. take all possible module combinations into the solver; then after each round, eliminate the results for each machine that have the least usage, then re-try again)? I don't think I can realistically say "One variable is > 0, every other variable is 0"?

fathom iron
distant igloo
#

You can probably do that with a MILP solver, but those are a looooot slower than IP solvers

upbeat hatch
#

(by setting the upper bound to zero, as a hack)

#

It's probably not perfect because it's based on the assumption that "If something is not used often, it's probably a byproduct"

fathom iron
#

Now that I'm actually playing through gleba I'm realizing that the solver probably shouldn't be trusted with anything bio-related since it doesn't handle fuel consumption.

#

which is also tricky since "prod" modules are basically anti-prod when it comes to nutrient consumption

#

any optimal solve of quality bioproducts almost certainly uses efficiency modules...

distant igloo
#

hm, the fuel doesn't have to be quality, so it shouldn't affect it too much at higher tiers of quality? But yeah, nutrient fuel is important on gleba

fathom iron
#

that's a good point, maybe it doesn't actually matter that much

hazy fractal
#

fuel production is relatively minimal on gleba though

#

80~90% of the nutrient consumption is in the pentapod egg recipe

distant igloo
#

Yeah, quality pentapod eggs are a whole different conversation

#

and quality bioflux for quality ores seems... annoying at best. you'd need a huge setup to avoid the bacteria spoiling before you get your next legendary bioflux

hazy fractal
#

yeah, I don't know why you'd do that on gleba instead of vulcanus

shell meadow
#

Is the speed beacon option trustworthy? it's slapping speed beacons on machines with quality modules

#

also the script is insisting that I upcycle uranium ore to epic no matter what cost settings I choose, very interesting

fathom iron
shell meadow
#

yep, I did see that and it makes sense

distant igloo
#

High quality speed modules with quality modules can make sense. Low quality speed modules are terrible, though

fathom iron
#

hey everyone I merged a change from @wild marlin that makes cool graphical outputs from the script

wild marlin
#

Wait did I make such a PR?

#

No it's zzh8829 not me

fathom iron
#

oh shoot nvm

#

I assumed that was you haha with the zz

wild marlin
#

My github name is dr-zzt

#

(FYI not a doctor yet)

fathom iron
#

is he in discord?

wild marlin
#

I don't know

patent pebble
fathom iron
versed moth
fathom iron
# versed moth what was best outcome for best module mix for superconductor? (only one stage) t...

this is what I get from the one_step_matrix_solver script:

python ./scripts/one_step_matrix_solver.py --module-slots 5 --additional-prod 50

optimizing recycling loop that turns ingredient quality 1 into product quality 5

q1 input per q5 output: 13.233909931435692
recipe q1 uses 1 quality modules and 4 prod modules
recipe q2 uses 1 quality modules and 4 prod modules
recipe q3 uses 1 quality modules and 4 prod modules
recipe q4 uses 1 quality modules and 4 prod modules
recipe q5 uses 0 quality modules and 5 prod modules
#

btw I just made some updates to the linear solver, there was a bug I didn't realize apparently speed penalties are capped at -80%, it now allows plant inputs (jellynut/yamako w/ default cost of 1), and --verbose prints input/output amounts for each recipe

versed moth
#

i think i found the answer somewhere u put as 4 prod/1 qual. but then what was difference between that and 5 prod or 5 qual

fathom iron
# versed moth i think i found the answer somewhere u put as 4 prod/1 qual. but then what was d...

I get 30.1 with only qual, only prod doesn't really make sense

python ./scripts/one_step_matrix_solver.py --module-slots 5 --additional-prod 50 --disable-prod

optimizing recycling loop that turns ingredient quality 1 into product quality 5

q1 input per q5 output: 30.09995129512883
recipe q1 uses 5 quality modules and 0 prod modules
recipe q2 uses 5 quality modules and 0 prod modules
recipe q3 uses 5 quality modules and 0 prod modules
recipe q4 uses 5 quality modules and 0 prod modules
recipe q5 uses 0 quality modules and 0 prod modules
#

but that's just setting it to a recipe that doesn't allow prod, so it uses 0 prod on the last step

versed moth
#

hmmm

#

i need more specific. assume super conductor recipe. so u only get 1 step. then recycle step

fathom iron
# versed moth i need more specific. assume super conductor recipe. so u only get 1 step. then ...

interesting, didn't realize the superconductor recycles into itself. Getting 191 of each input per legendary output.

python ./scripts/factorio_solver.py --output-item superconductor --input-items copper-plate=1 plastic-bar=1 holmium-plate=1 light-oil=0.2 --module-cost 0 --building-cost 0 --allowed-recipes superconductor superconductor-recycling
Solving...

Solution:
Objective value = 765.4482825957372

Inputs used:
input__normal__copper-plate: 191.3620706489343
input__normal__plastic-bar: 191.3620706489343
input__normal__holmium-plate: 191.3620706489343
input__normal__light-oil: 956.8103532446714

Buildings used: 493.9353491764136

Modules used: 2230.8908242375664

Machine layout:
Superconductor in Electromagnetic plant: normal 5Q
Superconductor (recycling) in Recycler: normal 4Q, uncommon 4Q, rare 4Q, epic 4Q
#

if you start to allow other recipes it does some weird clever tricks like making copper cables and recycling them, but this is also highly dependent on the cost function

python ./scripts/factorio_solver.py --output-item superconductor --input-items copper-plate=1 plastic-bar=1 holmium-plate=1 light-oil=0.2 --module-cost 0 --building-cost 0
Solving...

Solution:
Objective value = 503.0409394864801

Inputs used:
input__normal__copper-plate: 47.45947334153138
input__normal__plastic-bar: 219.41408689780448
input__normal__holmium-plate: 219.41408689780448
input__normal__light-oil: 83.7664617466988

Buildings used: 149.78230854775015

Modules used: 660.8155444397239

Machine layout:
Copper cable in Electromagnetic plant: normal 5P
Copper cable (recycling) in Recycler: normal 4Q
Holmium plate (recycling) in Recycler: normal 4Q
Plastic bar (recycling) in Recycler: normal 4Q
Superconductor in Electromagnetic plant: uncommon 5Q, rare 5Q, epic 5Q, legendary 5P
Superconductor (recycling) in Recycler: uncommon 4Q, rare 4Q, epic 4Q
versed moth
#

blah so many variables now

#

wait, it doesnt use mix modules?

#

i thought in here it would use 4P +1Q

distant igloo
#

Crafting superconductors isn't involved in a loop, which changes the math

fathom iron
versed moth
#

okay

fathom iron
#

wonder why they did that for superconductors

distant igloo
#

OTOH this chain would be a pain in the ass to actually build, because you'll end up with an imbalance between the types

fathom iron
#

it's not really a plate or bar

distant igloo
#

How much worse is it if you craft the inputs to superconductors with prod instead of quality?

versed moth
#

so if it would change to supercapacitor (it doesnt follow rule of super conductor) then it would 4P +1Q then recycle? how much is that different vs 5P or 5Q?

distant igloo
#

That recipe chain is much less annoying to build in practice

fathom iron
#

yeah just using --allowed-recipes with only the one craft/recycle is probably better

versed moth
#

actually this is nice, if it recycles into itself, use full Quality, right?

#

which would apply to most first stage items, like holmium plate

fathom iron
versed moth
#

yea i figured

hazy fractal
#

restricted recipe chains might work nicely. let users specify a tolerable waste %. start with a full solve, then keep iteratively removing recipes as long as the required inputs don't increase more than the specified waste %

shell meadow
#

Yeah I’d love support for incrementally removing random recipes for armor and stuff. I suppose I can write a little script

shell meadow
#

Not sure if anything changed, but I'm seeing great regularization out of speed beacon setting with building cost setting. Mixed prod/quality modules don't actually make sense because beaconed prod machines have enormous throughput compared to quality modules

versed moth
#

better yield

shell meadow
#

Sure, but they're less convenient to scale.

versed moth
#

similar to full quality basically, just copy paste

#

full quality builds gets large, but it isnt even close to like 2.5k spm vanilla

fathom iron
#

I did fix the 20% minimum speed issue, which was causing a lot of weird results previously

versed moth
#

Do you know rate for asteroid chunks and/or crafting speed to get 1 to legendary?
From my P graph it seems around 40-50 per legendary.

I'm trying to compare it against mining rate then recycling

meager kiln
#

did you do all 3 asteroids or substitute 80%?
cause im getting 90 on average with 80%
i think separate shouldnt matter but not 100% sure

versed moth
#

only iron, but i break q2/q3/q4 as well

meager kiln
#

oh nvm made a mistake
im getting 48 now

fathom iron
#

I haven't checked, but I'm starting to wonder if quality science ever wins when optimizing for modules or number of buildings instead of inputs

distant igloo
#

Well science requires zero modules normally, so module count isn't going to favor it

fathom iron
#

no, if you use buildings with modules in them to make the science, and "minimize modules" just means making a more compact setup

distant igloo
#

Building count might, but speed+prod is better than speed+qual, so I suspect that will also lean prod. (Thought recipes that don't take prod might take quality?)

fathom iron
#

oh you mean like if I allowed the solver to check buildings with no modules in them

distant igloo
#

Yeah

#

Buildings with no modules are pretty good when modules are your cost function 🙂

fathom iron
#

this is making me re-think the whole cost function. Maybe instead of the number of inputs used per output, or the cost of the buildings used in the setup, it should just be the number of buildings? Maybe what we really want is the most compact setup possible?

sullen bluff
fathom iron
sullen bluff
#

that's an exellent question actually, i don't know, i think i might have went the first rout

#

to utilize every input i can

#

depends on science too

fathom iron
#

more generally, I think extra input belts should be thought more of as "buildings" in some sense than as the "thing that must always be optimized", especially if you're not worried about ore patches running out

sullen bluff
#

about 1\10th buiding btw, if we are talking about quality modules and prod modules, the difference between them is 10 percent speed (-5 and -15)

#

so for most sciences the ammount of machines wont be more than halfed with any module configuration

fathom iron
#

yeah it's a very unrealistic example, more just to demonstrate that it's not obvious how to think about it

sullen bluff
#

exept cryogenic plants

fathom iron
#

and it's a little annoying arguing w/ romayne, who keeps insisting that "speed always bad" even though the linear solver keeps wanting them even in the quality steps, shrug...

sullen bluff
#

well, He is just a perfectionist haha, not a drop of resources should be wasted

fathom iron
#

oh no god forbid I waste lava

sullen bluff
#

yeah, gotta change your way of thinking sometimes

fathom iron
#

I mean even after all this LP discussion even I don't know the best answer lol, just that it's way trickier/more subtle than people realize

sullen bluff
#

you know Rimworld, that's a game that changed how i play factorio, on high difficulties it doesn't allow you to be perfectionist at all

fathom iron
#

interesting, never played it

sullen bluff
#

it forces you to use everything only to survive

#

it's a colony simulator with 137 hours AVERAGE time played

#

very addictive highly recomment

#

d

#

also i am banned from the official surver because i kept accidentally sending my colony name -_-

distant igloo
#

Another thing that I don't know how to model: some of these recipes are probabilistic, and you might get an excess of one product. What do you do with it?

distant igloo
#

Recycling belts gives you plates and gears. What do you do with extra gears? What do you do with extra plates?

sullen bluff
#

No

#

if you grind for high quality belts

#

you recycle and priority input those quality gears in assemblers for belts

#

such systems never overflow and should not overflow if done correctly

distant igloo
#

Are you making high quality gears elsewhere? Plates too?

#

What do you do with extra rare plates where you don't have any rare gears to combine them with?

sullen bluff
distant igloo
#

The output is probabilistic and may drift from the right proportion

sullen bluff
distant igloo
#

If you try this with just a short sushi belt, it will deadlock due to this

sullen bluff
#

gimme a sec ill show it to you

#

everything i had was made like this

#

for modules too, and never backed up

distant igloo
#

Module 2s take in 4 module 1s, so the recycling outputs 1. No probability there. Belts take one gear, so they output 0.25 gears. Probability is an issue

sullen bluff
#

hm ok

#

than sorry i don't think i can give good advice here, but some guys here done very good math, ask them ig

distant igloo
#

That is, in fact, what I was doing 😛

fathom iron
distant igloo
#

Yeah, in theory

#

Recycling down to nothing definitely works. I'm curious what the LP-approved optimal way is though

fathom iron
#

for probabilities I just use EV. Is there a particular recipe or item you were interested in?

fathom iron
fair arrow
#

Posting to follow for catching up later

keen thistle
#

linear programming is dark magic for me, imma lurk

fathom iron
distant igloo
#

This seems like another case where you should allow empty module slots

fathom iron
#

yeah

#

I don't think it would be hard to add the extra for loop, but I'm wondering how much it would slow it down, basically turning everything from O(N)ish to O(N^2)ish

#

for the combinatorics of modules

#

even checking the speed modules makes it noticeably slower

distant igloo
#

You could add a special case of no modules, and not consider partially filled buildings

#

There are probably a few other cases that are unlikely to be useful, e.g. some speed modules and some empty spots, or speed modules without some other kind of module

fathom iron
#

speed is fairly easy to check since it only checks it coming from beacons, but it basically just adds an extra O(N) overhead factor for each speed modifier being checked

#

I don't think it's worth checking speed in the building's modules

#

but having empty modules in the buildings could be useful

distant igloo
#

Makes sense

astral barn
#

+1 to the request of allowing empty module slots. As you have free time of course. It feels wrong see quality mods in liquid recipes. This would always increase the building cost since they'd run slower, right?

RE: performance, maybe it can be optional flag if you don't want to increase the baseline compute time—assuming this doesn't make the whole thing more complicated

fathom iron
#

I speculated a bit on why I think it was picking qual over prod in some liquid cases in the issue thread on github. Basically the speed penalty is worse for prod than quality, so if an output is making everything from scrap, and holmium isn't the limited factor, then it might not need the entire prod bonus relative to other ingredients, and so it would be better to make it with a smaller speed penalty if the prod isn't needed, hence the quality module taking its place.

astral barn
#

I think I'm missing something. How is speed worse for prod than quality?

fathom iron
#

-15% instead of -5%

#

for the tier 3s

#

to clarify, prod has a bigger speed penalty to the machine than qual, so it would end up with more machines

astral barn
#

oh oh, okay. Yeah that part makes sense to me. Then I misread your comment here 😅

I'm not extremely familiar with the codebase but skimming over it seems right now there is no possibility for an empty module, which would be a lower building & module cost in some cases. And you are currently deciding whether or not to implement that as a feature.

fathom iron
astral barn
#

awesome! I totally get priorities too. I will be watching from the sidelines 🙂 thanks for all the work

fathom iron
astral barn
#

Just realized after reading through the code more carefully that I had been neglecting the "check-speed-modules" arg. Doh. This kinda gets closer to what I expected. It doesn't really give useful results (IMO) for smaller output amounts. Changing to a "building count" cost as you described in the github comment would probably tune this part better as well.

I see what you mean about extending the loop. You'd have to add yet another iterable to the cartesian product, right? The flat 16 from speed beacons already blows up runtime so your point is well made.

fathom iron
#

pretty much yeah, though it may need to be implemented as two for loops since the quality modules would only go up to the number of modules, so it's not really a full cartesian product and more like a triangular number