factoriocalc package

Main package. Most symbols in submodules are available in this package. If a symbol is not mentioned as belonging to a submodule, the location should be considered an implementation detail.

Fractions

frac(num=0, den=None, *, float_conv_method='if int')

return a fraction that automatically convertes to an int when applicable

Parameters:
  • num – a number of any type or string, the string may be an int, decimal, or a fraction of the form ‘num/den’.

  • den – denominator of fraction, may be an int or Frac. If defined num must also be an int or Frac.

  • float_conv_method – one of disallow, if int, exact, or round

Returns:

Frac or an int

div(num, den)

equivalent to num/den but returns a Frac or int instead of a float.

class Frac

Class used internally for all calculation, should normally use frac to create a Frac. See fracs.Frac for complete documentation.

Core

Default: DefaultType
class Ingredient(name, order)

Bases: Immutable

Base class for all items.

__slots__ = ('name', 'order', '_sortKey')
__init__(name, order)
property alias
property descr
__str__()

Return str(self).

__repr__()

Return repr(self).

__matmul__(rate)
recipes()
__lt__(other)

Return self<value.

__le__(other)

Return self<=value.

__gt__(other)

Return self>value.

__ge__(other)

Return self>=value.

name
order
class Item(name, order, stackSize, fuelValue=0, fuelCategory='')

Bases: Ingredient

__slots__ = ('stackSize', 'fuelValue', 'fuelCategory')
__init__(name, order, stackSize, fuelValue=0, fuelCategory='')
stackSize
fuelValue
fuelCategory
class Fluid(name, order)

Bases: Ingredient

__slots__ = ()
class Research(name, order)

Bases: Ingredient

__slots__ = ()
class Electricity(name, order)

Bases: Ingredient

__slots__ = ()
class Module(name, order, stackSize, effect, limitation=None, limitationBlacklist=None)

Bases: Item

__slots__ = ('effect', 'limitation')
__init__(name, order, stackSize, effect, limitation=None, limitationBlacklist=None)
__mul__(num)
__rmul__(num)
effect
limitation
class MachineBase(*args, **kwargs)

Bases: object

flows(throttle=None, includeInner=True)
flow(item, throttle=None)
__mul__(fac)
__rmul__(fac)
__add__(other)
__lt__(other)

Return self<value.

__gt__(other)

Return self>value.

print(out=None, prefix='')
pprint(out=None, prefix='', suffix='\n')
static __new__(cls, *args, **kwargs)
__eq__(other)

Return self==value.

__hash__ = None
__init__() None
__match_args__ = ()
__repr__()

Return repr(self).

class Machine(*args, **kwargs)

Bases: MachineBase

A entity that used directly or indirectly to produce something.

blueprintInfo: dict = None
__init__(*, throttle=1, unbounded=False)
throttle: Rational
unbounded: bool
property machine
property num
property recipe
property descr
alias = 'Machine'
resetThrottle()
solve()
__invert__()
__setattr__(prop, val)

Implement setattr(self, name, value).

summarize()
__repr__()

Return repr(self).

__str__()

Return str(self).

flatten()
property inputs
property outputs
property products
property byproducts
bonus() Bonus
energyUsage(throttle)
__eq__(other)

Return self==value.

__hash__ = None
__match_args__ = ('throttle', 'unbounded', 'blueprintInfo', '_Machine__flows1', '_Machine__flows')
class CraftingMachine(*args, **kwargs)

Bases: Machine

An entity that produce something.

name = 'crafting-machine'
craftingSpeed = 1
baseEnergyUsage = 0
energyDrain = 0
pollution = 0
craftingCategories = {}
__init__(recipe=None, **kws)
recipe: Recipe = None
__setattr__(prop, val)

Implement setattr(self, name, value).

__eq__(other)

Return self==value.

__hash__ = None
__match_args__ = ('throttle', 'unbounded', 'blueprintInfo', '_Machine__flows1', '_Machine__flows', 'recipe')
class Mul(*args, **kwargs)

Bases: MachineBase

A group of identical machines.

num must be positive but fractional values are permitted.

__init__(*args)
num: Rational
machine: MachineBase
__setattr__(prop, val)

Implement setattr(self, name, value).

__str__()

Return str(self).

__repr__()

Return repr(self).

property inputs
property outputs
property products
property byproducts
property recipe
resetThrottle()
solve()
flatten()
summarize()
__eq__(other)

Return self==value.

__hash__ = None
__match_args__ = ('num', 'machine')
class Group(*args, **kwargs)

Bases: Sequence, MachineBase

A group of machines.

__init__(*machines)
machines: List[MachineBase]
property machine
property num
flatten()
__iter__()
__getitem__(idx)
__len__()
__repr__()

Return repr(self).

__str__()

Return str(self).

__add__(other)
print(out=None, prefix='')
pprint(out=None, prefix='', suffix='\n')
simplify()
sorted()
summary(out=<_io.TextIOWrapper name='<stdout>' mode='w' encoding='utf-8'>, *, prefix='', includeSolvedBoxFlows=True, includeMachineFlows=True, includeBoxDetails=True, flowsItemFilter=None)
summarize()
setThrottle(throttle, filter=<function Group.<lambda>>)
adjThrottle(factor, filter=<function Group.<lambda>>)
resetThrottle()
solve()
find(recipe=None, *, input=None, output=None, machine=None, inputs=(), outputs=(), recipes=(), machines=())
__eq__(other)

Return self==value.

__hash__ = None
__match_args__ = ('machines',)
class Flow(item, rateOut, rateIn, rateSelf, adjusted, underflow, annotation)

Bases: NamedTuple

item: Ingredient

Alias for field number 0

rateOut: Rational

Alias for field number 1

rateIn: Rational

Alias for field number 2

rateSelf: Rational

Alias for field number 3

adjusted: bool

Alias for field number 4

underflow: bool

Alias for field number 5

annotation: str

Alias for field number 6

__bool__()
rate()
annotations()
netFlow()
__str__(*, altUnit=None)

Return str(self).

print(out=None, prefix='', altUnit=None)
__repr__()

Return repr(self).

__mul__(factor)

Return self*value.

__rmul__(factor)

Return value*self.

copy(*, factor=1, adjusted=None, underflow=None, annotation=None)
__match_args__ = ('item', 'rateOut', 'rateIn', 'rateSelf', 'adjusted', 'underflow', 'annotation')
static __new__(_cls, item: Ingredient, rateOut: Rational = 0, rateIn: Rational = 0, rateSelf: Rational = 0, adjusted: bool = False, underflow: bool = False, annotation: str = None)

Create new instance of Flow(item, rateOut, rateIn, rateSelf, adjusted, underflow, annotation)

__orig_bases__ = (<function NamedTuple>,)
__slots__ = ()
class OneWayFlow(item, rate, annotations)

Bases: NamedTuple

item: Ingredient

Alias for field number 0

rate: Rational

Alias for field number 1

annotations: str

Alias for field number 2

__str__()

Return str(self).

__neg__()
__repr__()

Return repr(self).

asFlow()
__match_args__ = ('item', 'rate', 'annotations')
static __new__(_cls, item: Ingredient, rate: Rational = 0, annotations: str = '')

Create new instance of OneWayFlow(item, rate, annotations)

__orig_bases__ = (<function NamedTuple>,)
__slots__ = ()
class FlowsState(value)

Bases: OrdEnum

An enumeration.

OK = 0
UNDERFLOW = 1
UNSOLVED = 2
INVALID = 3
ok()
class Flows

Bases: object

A sequence of flows.

Individual flows are stored as a dict in the byItem field.

__slots__ = ('byItem', '_byproducts', 'state')
flow(item)

Returns the flow for item or an empty flow if item not in byItem.

rate(item)

Returns the flow rate for item.

__iter__()
__repr__()

Return repr(self).

__str__()

Return str(self).

items()

Returns self.byItem.keys()

print(out=None, prefix='  ', *, sortKey=None, altUnit=None)
__getitem__(item)

Returns the flow for item or an empty flow if item not in byItem.

__len__()
products()
byproducts()
mul(num, markAsAdjusted=False)
filter(*, items)
__add__(obj)
__radd__(obj)
__mul__(num)
__rmul__(num)
__eq__(other)

Return self==value.

byItem
state
__hash__ = None
class SimpleFlows(_mutableFlows=None)

Bases: Flows

__init__(_mutableFlows=None)
byItem
state
output(item)
input(item)
outputs()
inputs()
class NetFlows(_mutableFlows=None)

Bases: Flows

__init__(_mutableFlows=None)
byItem
state
output(item)
input(item)
outputs()
inputs()
internal()
surplus()
lackof()
class Effect(speed: Rational = 0, productivity: Rational = 0, consumption: Rational = 0, pollution: Rational = 0)

Bases: _Effect

class Bonus(*args, **kwargs)

Bases: _Effect

static __new__(cls, *args, **kwargs)

Create new instance of _Effect(speed, productivity, consumption, pollution)

class Recipe(name, category, inputs, products, byproducts, time, order)

Bases: Immutable

A recipe to produce something.

__slots__ = ('name', 'category', 'inputs', 'products', 'byproducts', 'time', 'order')
__init__(name, category, inputs, products, byproducts, time, order)
property alias
property descr
property enabled
property origRecipe
property outputs
__lt__(other)

Return self<value.

__le__(other)

Return self<=value.

__gt__(other)

Return self>value.

__ge__(other)

Return self>=value.

__str__()

Return str(self).

__repr__()

Return repr(self).

str()
eqv(other)

Returns true if other is equivalent to self and not just the same object.

produce(machinePrefs=Default, fuel=None, machine=None, modules=(), beacons=(), beacon=Default, rate=None, inputRate=None)
__call__(machinePrefs=Default, fuel=Default, machine=None, modules=Default, beacon=Default, beacons=Default, rate=None, inputRate=None)

Call self as a function.

name
category
inputs
products
byproducts
time
order
class RecipeComponent(num, catalyst, item)

Bases: NamedTuple

num: Rational

Alias for field number 0

catalyst: Rational

Alias for field number 1

item: Item

Alias for field number 2

product()
__str__()

Return str(self).

__match_args__ = ('num', 'catalyst', 'item')
static __new__(_cls, num: Rational, catalyst: Rational, item: Item)

Create new instance of RecipeComponent(num, catalyst, item)

__orig_bases__ = (<function NamedTuple>,)
__repr__()

Return a nicely formatted representation string

__slots__ = ()
IGNORE = -100
exception InvalidModulesError(m)

Bases: ValueError

__init__(m)
maxInputs(*args)
class MachinePrefs(*args)

Bases: tuple

__repr__()

Return repr(self).

static __new__(cls, *args)
__add__(other)

Return self+value.

__radd__(other)
__mul__(num)

Return self*value.

__rmul__(num)

Return value*self.

withBeacons(beacon, mapping)
rcpByName
itmByName
mchByName
recipesThatMake
recipesThatUse

mch module

Classes for factorio entities.

Only entities needed in manufacturing something are included. For example, assmebling machines and beacons are included but power poles are not.

The class name is the same as the internal name but converted to title case with any - removed. For example, mch.AssemblingMachine3.

The contents of this module are dynamic and controlled via the config.gameInfo context variable.

_find(toFind)

Perform a case insensitive search of any occurrence of the substring toFind in the descr field of members.

itm module

Symbols for items and fluids in factorio.

The name of the symbol is the same as the internal name but with - converted to _. For example, to refer to an “electronic-circuit” use itm.electronic_circuit.

The contents of this module are dynamic and controlled via the config.gameInfo context variable.

_find(toFind)

Perform a case insensitive search of any occurrence of the substring toFind in the descr field of members.

When the gameInfo context variable is configured for the base game this module also provides a few special items:

_combined_research

Result of rcp._combined_research.

_military_research

Result of rcp._military_research.

_production_research

Result of rcp._production_research.

rcp module

Symbols for recipes (Rcp) in factorio.

The name of the symbol is the same as the internal name but with - converted to _. For example, to refer to the recipe for an “electronic-circuit” use rcp.electronic_circuit.

The contents of this module are dynamic and controlled via the config.gameInfo context variable.

_find(toFind)

Perform a case insensitive search of any occurrence of the substring toFind in the descr field of members.

When the gameInfo context variable is configured for the base game this module also provides some special recipes:

space_science_pack

Recipe to produce 1000 itm.space_science_pack in a RocketSilo.

_combined_research

Recipe to consume all 7 science packs at a rate of 1/s in a FakeLab.

_military_research

Recipe to consume all but the production science pack at a rate of 1/s in a FakeLab.

_production_research

Recipe to consume all but the military science pack at a rate of 1/s in a FakeLab.

config module

displayUnit: ContextVar

Display units, the value should be set to one of the DU_* presets.

Defaults to DU_SECONDS

machinePrefs: ContextVar

Machine to use when instantiating recipes, The value is a sequence of machines (with or without a recipe) to try. The MP_* presets provide some common configuration for vanilla gameplay.

When selecting a machine to use the first best match is used. If the machine has a matching recipe associated then that will be given priority. In addition a machine with compatible modules will be given priority.

Does not have a default. Must be set before calling a recipe to instantiate it or using produce.

recipePrefs: ContextVar
defaultFuel: ContextVar

Defaults to itm.coal.

gameInfo: ContextVar

Internal variable to control the contents of the mch, itm, rcp and preset modules.

presets module

Useful presets.

The contents of this module are dynamic and controlled via the config.gameInfo context variable.

When the gameInfo context variable is configured for the base game this module provides:

MP_EARLY_GAME = MachinePrefs(mch.AssemblingMachine1(), mch.StoneFurnace(fuel=None))
MP_LATE_GAME = MachinePrefs(mch.AssemblingMachine3(), mch.ElectricFurnace())
MP_MAX_PROD(level=3, beacon=None, beacons=None)
SPEED_BEACON = mch.Beacon(2*itm.speed_module_3)
sciencePacks: set = {itm.automation_science_pack, itm.logistic_science_pack, itm.production_science_pack, itm.utility_science_pack, itm.chemical_science_pack, itm.space_science_pack, itm.military_science_pack}

Units

class Unit(abbr, sep, conv)

Bases: NamedTuple

abbr: str

Alias for field number 0

sep: str

Alias for field number 1

conv: Rational

Alias for field number 2

__match_args__ = ('abbr', 'sep', 'conv')
static __new__(_cls, abbr: str, sep: str, conv: Rational)

Create new instance of Unit(abbr, sep, conv)

__orig_bases__ = (<function NamedTuple>,)
__repr__()

Return a nicely formatted representation string

__slots__ = ()
wagonsPerUnit(item, rate, conv)
wagonsPerMinute(*args)
UNIT_SECONDS = Unit(abbr='s', sep='/', conv=1)
UNIT_MINUTES = Unit(abbr='m', sep='/', conv=60)
UNIT_HOURS = Unit(abbr='h', sep='/', conv=3600)
UNIT_EXPRESS_BELTS = Unit(abbr='eb', sep=' ', conv=Frac(1, 45))
UNIT_FAST_BELTS = Unit(abbr='fb', sep=' ', conv=Frac(1, 30))
UNIT_TRANSFER_BELTS = Unit(abbr='tb', sep=' ', conv=Frac(1, 15))
UNIT_MEGAWATT = Unit(abbr='MW', sep=' ', conv=1)
UNIT_STACKS_PER_SEC = Unit(abbr='s/s', sep=' ', conv=<function <lambda> at 0x7fd0f774d1b0>)
UNIT_STACKS_PER_MIN = Unit(abbr='s/m', sep=' ', conv=<function <lambda> at 0x7fd0f774d240>)
UNIT_WAGONS_PER_MIN = Unit(abbr='w/m', sep=' ', conv=<function wagonsPerMinute at 0x7fd0f774d120>)
DU_SECONDS = ((Electricity, Unit(abbr='MW', sep=' ', conv=1)), (None, Unit(abbr='s', sep='/', conv=1)))
DU_MINUTES = ((Electricity, Unit(abbr='MW', sep=' ', conv=1)), (None, Unit(abbr='m', sep='/', conv=60)))
DU_HOURS = ((Electricity, Unit(abbr='MW', sep=' ', conv=1)), (None, Unit(abbr='h', sep='/', conv=3600)))
DU_EXPRESS_BELTS = ((Item, Unit(abbr='eb', sep=' ', conv=Frac(1, 45))), (Electricity, Unit(abbr='MW', sep=' ', conv=1)), (None, Unit(abbr='s', sep='/', conv=1)))
DU_FAST_BELTS = ((Item, Unit(abbr='fb', sep=' ', conv=Frac(1, 30))), (Electricity, Unit(abbr='MW', sep=' ', conv=1)), (None, Unit(abbr='s', sep='/', conv=1)))
DU_TRANSFER_BELTS = ((Item, Unit(abbr='tb', sep=' ', conv=Frac(1, 15))), (Electricity, Unit(abbr='MW', sep=' ', conv=1)), (None, Unit(abbr='s', sep='/', conv=1)))
DU_STACKS_PER_SEC = ((Item, Unit(abbr='s/s', sep=' ', conv=<function <lambda> at 0x7fd0f774d1b0>)), (Electricity, Unit(abbr='MW', sep=' ', conv=1)), (None, Unit(abbr='s', sep='/', conv=1)))
DU_STACKS_PER_MIN = ((Item, Unit(abbr='s/m', sep=' ', conv=<function <lambda> at 0x7fd0f774d240>)), (Electricity, Unit(abbr='MW', sep=' ', conv=1)), (None, Unit(abbr='s', sep='/', conv=1)))
DU_WAGONS_PER_MIN = ((Electricity, Unit(abbr='MW', sep=' ', conv=1)), (None, Unit(abbr='w/m', sep=' ', conv=<function wagonsPerMinute at 0x7fd0f774d120>)))

Boxes and Produce

class BoxBase(*args, **kwargs)

Bases: MachineBase

property num
property machine
property recipe
__repr__()

Return repr(self).

__str__()

Return str(self).

class Equal(*args)

Bases: Constraint

__slots__ = 'expressions'
__repr__()

Return repr(self).

__str__()

Return str(self).

__getitem__(index)
__len__()
__init__(*args)
expressions
class AtLeast(lhs, rhs)

Bases: Inequality

__slots__ = ()
symbol = '>='
class Box(*args, **kwargs)

Bases: BoxBase

Wraps a group to restrict inputs or outputs.

MIN_PRIORITY = -100
MAX_PRIORITY = 100
class Outputs(vals=None, priorities=None)

Bases: _ExternalFlows

__slots__ = ()
__setitem__(item, rate)

Set self[key] to value.

class Inputs(vals=None, priorities=None)

Bases: _ExternalFlows

__slots__ = ()
__setitem__(item, rate)

Set self[key] to value.

class OtherFlows(vals=None, priorities=None)

Bases: _ExternalFlows

__slots__ = ()
__setitem__(item, rate)

Set self[key] to value.

class SimpleConstraints(vals=None)

Bases: _Dict

__slots__ = ()
__str__()

Return str(self).

__setitem__(item, rate)

Set self[key] to value.

class OtherConstraints(iterable=(), /)

Bases: list

__str__()

Return str(self).

class Priorities(vals=None)

Bases: _Dict

__slots__ = ()
__str__()

Return str(self).

__setitem__(key, priority)

Set self[key] to value.

__init__(*args, name=None, inner=None, outputs=None, extraOutputs=(), outputTouchups=(), outputsLoose=False, inputs=None, extraInputs=(), inputTouchups=(), inputsLoose=True, unconstrained=(), constraints=(), priorities=None, allowExtraInputs=False)

Create a new box.

A box is a wrapper around a group with additional constraints to limit flows. For example it is rare for satellite machine to be running 100% of the time. This means that simply estimating the maximum flows will not give you an accurate picture of the resources needed, by grouping the satellite with a rocket silo, wrapping it in a box, and then solving it, you can can a better idea of the resources needed for creating space science packs. After solving, the satellite machine will be throttled to produce just enough satellites for the rocket silo.

Boxes can nest inside one another.

Also see box(), which is a shortcut to both create a box and then solve it.

args

Positional arguments, can optically include, name, and/or inner (in that order).

name

A name for the box

inner

A Group.

outputs, extraOutputs, outputTouchups, inputs, extraInputs, inputTouchups

A sequence or mapping of outputs and inputs. The key value can either be a rate in seconds, None, or a priority. If a list, elements can either be an item, a tuple of the form (item, rate) (as generated with the @ operator), or a flow. If the rate is a string that starts with ‘p’ or ‘p:’ than the number after the prefix will be interpreted as a priority.

If outputs or inputs is unspecified than they will be derived automatically based on if the flow is internal or not. The outputTouchups and inputTouchups can be used to adjust the inputs or outputs afterwards.

extraOutputs or extraInputs can be used to specify auxiliary flows and is equivalent to setting the priority to IGNORE.

outputsLoose

If True (default False) than all output rates will become constraints

inputsLoose

If True (the default) than all input rates will become constraints

unconstrained

Ignored flows. Neither input or outputs and the exact values can be either postive or negative depending on the machine configuration. The values are completly ignored by the solver.

constraints

Extra constraints for the solver. It can either be a mapping of simple constraints, or a list of equations.

If a mapping then the flow for the item (the key) will need to be at least the given rate. Positive values will constrain outputs and negative values will constrain inputs. For example, {itm.plastic_bar: 2} will add a constraint to produce plastic bars at a rate of at least 2/s and {itm.plastic_bar: -2} will add a constraint to consume plastic bars at a rate of 2/s max (inclusive).

If a list, then it a list of simple equations that must be true. An equation currently is one of Equal(term1, term2, ...) or AtLeast(lhs, rhs). Each term in either a number, an item, or a tuple. For example: Equal(itm.uranium_fuel_cell, (-1, itm.used_up_uranium_fuel_cell))

priorities

A mapping of priorities for the solver. The key is either an item or a recipe. The value in a number between -100 and 100 with larger values having a higher priority. The default priority for outputs is 0. The constant IGNORE can be used for the lowest priority (-100) and has special meaning to the solver. Input priorites are currently ignored unless the constant IGNORE is used. Recipe priorities are supported, but should be positive.

allowExtraInputs

 

inner
name
priorities
simpleConstraints
otherConstraints
unconstrained
unconstrainedHints
outputs
inputs
updateName_()
property products
property byproducts
internal()
print(out=None, prefix='')
summary(out=None, *, prefix='', includeSolvedBoxFlows=True, includeMachineFlows=False, includeBoxDetails=True, flowsItemFilter=None)
solved()
solve()

Solve the box so all contraints are met.

Returns a SolveRes enum with the result. See the SolveRes documenation for meaning of the enum values.

solver(**kwargs)

Return a solver instance for debugging or more control over the solve process.

flowSummary(out=None, includeInner=False)
internalFlows()
bottlenecks()
find(*args, **kwargs)
resetThrottle()
finalize(*, roundUp=True, recursive=True, _res=None)

Finalize the result.

Finalize the result by turning unbounded throttles into Mul. If the unbounded throttle is 0 the machine is removed. If roundUp is True (the default) then also round up multiples of machines (i.e. Mul) and adjust the throttle to compensate. If recursive is True (the default) than recurse into any inner boxes.

Returns an instance of FinalizeResult.

finalizeAll(roundUp=True)

Finalize everything.

Equivalent to self.finalize(roundUp, recursive = True)

class BlackBox(*args, **kwargs)

Bases: BoxBase

Wrap a box to hide it’s internals.

When used with the solver, the solver will treat the black box as a simple machines and throttle all internal machines uniformity. This allows them to be used inside an unbounded box and can also simplify the solve process.

__init__(box, *, name=None)
property inputs
property outputs
property products
property byproducts
resetThrottle()
__invert__()
finalizeGroup(grp, *, roundUp=True, recursive=True)
class SolveRes(value)

Bases: OrdEnum

Result of solving a linear equation system.

The values of the enum are subject to change, but the relative order should be stable.

UNSOLVED = -2

not yet solved

NOOP = -1

already solved

OPTIMAL = 1

a solution was found, no test for uniqueness was done

UNIQUE = 2

all output machines are at there maxium giving the constraints

MULTI = 3

output machines are at there maxium giving the constraints but there are multiple possible configurations

OK = 4

a solution was found but some machines are not at there maxium output, to make the solution unique add additional constraints or priorities

PARTIAL = 5

a partial solution was found by removing constraints

UNBOUNDED = 6

the system is unbounded, a partial solution was found by setting unbounded vars to 0

ok()
notok()
failed()
box(*args, minSolveRes=None, **kwargs)

Create a Box and then solve it.

Will raise NonUniqueSolutionError if the solver returned a result larger than minSolveRes (default SolveRes.MULTI) or SolveFailedError if the solve failed.

All other parameters are passed to Box.

produce(outputs, using=(), *, stopAt=(), fuel=None, constraints=(), name=None, abortOnMultiChoice=True, recursive=True, roundUp=False, minSolveRes=SolveRes.MULTI, solve=True)

Create a factory to produce outputs.

It works in two stages the first is select appropriate recipes and machines to produce the given outputs and the second is to determine the nunber of machines needed using the same solver used by the solve method in Box.

The paramaters are:

outputs

sequence or mapping of outputs, rates are per second and can be None if inputs are well specified.

using

an optional mixed type sequence used to guide the selection of what recipes to use and when to stop.

If an item is given it will try and select recipes that use that item and stop once it is used. If paired with a rate (using the ‘@’ operator) then will use that item at the given rate.

If a recipe is given the solver will attempt to use that recipe if possible and keep going. If more than one recipe is specified for a given output both will be used and the solver step will attemt to determine the best combination.

If a machine instance is given that machine configuration will be used when applicable. If a machine instance recipe is not None that machine configuration will only be used for the given recipe. If a matching machine is not found, produce will use config.machinePrefs.

fuel

item to use as fuel when applicable, if None will use config.defaultFuel

recursive

 

roundUp

Round up multiple of machines to integer values and adjust the throttle to compensate.

minSolveRes

The minimum acceptable solver result. Defaults to SolveRes.MULTI.

The result is a dataclass with the following fields:

factory

the resulting factory as an instance of Box

solveRes

the result of the second stage solver

extraOutputs

list of auxiliary outputs; if these outputs are not consumed somehow than the entiry factory is likely to grind to a halt

extraInputs

list of inputs used not specified in using if no inputs are specified this list will be empty

unusedInputs

list of unused inputs

May also throw the following errors (all subclass ValueError)

merge(*args, mergeFun=<built-in function add>)
union(*args)
class ProduceResult(factory: factoriocalc.box.Box = None, solveRes: factoriocalc.solver.SolveRes = <SolveRes.UNSOLVED: -2>, extraOutputs: list = <factory>, extraInputs: list = <factory>, unusedInputs: list = <factory>)

Bases: object

factory: Box = None
solveRes: SolveRes = -2
extraOutputs: list
extraInputs: list
unusedInputs: list
__eq__(other)

Return self==value.

__hash__ = None
__init__(factory: ~factoriocalc.box.Box | None = None, solveRes: ~factoriocalc.solver.SolveRes = SolveRes.UNSOLVED, extraOutputs: list = <factory>, extraInputs: list = <factory>, unusedInputs: list = <factory>) None
__match_args__ = ('factory', 'solveRes', 'extraOutputs', 'extraInputs', 'unusedInputs')
__repr__()

Return repr(self).

exception MultipleChoiceError

Bases: ValueError

exception SolveFailedError(res)

Bases: ValueError

__init__(res)
exception NonUniqueSolutionError(res)

Bases: ValueError

__init__(res)

Blueprints

class Blueprint(bp)

Bases: object

__init__(bp)

Create a blueprint from a decoded JSON object.

See also importBlueprint.

convert(*, burnerFuel=None, recipes=None) Group

Convert a blueprint into a nested Group.

The outer group contained two inner groups. The first inner group is the factory, and the second is the beacons the factory used.

If burnerFuel is defined than use that item for machines that require a fuel source, otherwise config.defaultFuel is used. If recipes are defined it is expected to be a mapping of machines classes to recipes and will be used as the recipe for that machine if none is defined.

The original blueprint info for each machine is stored in the blueprintInfo field.

group(**convertArgs) Group

Shorthand for self.convert(**convertArgs)[0].simplify().sorted()

class BlueprintBook(bp)

Bases: object

__init__(bp)

Create a blueprint book from a decoded JSON object.

See also importBlueprint.

__getitem__(idx)
__len__()
find(label) Blueprint

Find the blueprint with label.

labels() list[str]
importBlueprint(arg=None, *, file=None)

Decode arg to a blueprint or blueprint book. If arg is a pathlib.Path or the file argument is provided than read the contents from a file, otherwise decode the string provided.

JSON Conversion

toJsonObj(other, customRecipeCache=None)

Convert a factory to a dict that can then be converted to JSON

INCOMPLETE. Do a round trip test before using for anything serious.

fromJsonObj(jsonObj, customRecipeCache=None)

Convert a dict (presumably created from JSON) to a factory

Helpers

withSettings(settings, fun, *args, **kwargs)

helper function to locally set a ContextVar

class FakeLab(*args, **kwargs)

Bases: CraftingMachine

__eq__(other)

Return self==value.

__hash__ = None
__match_args__ = ('throttle', 'unbounded', 'blueprintInfo', '_Machine__flows1', '_Machine__flows', 'recipe')
__repr__()

Return repr(self).

class FakeBeacon(*args, **kwargs)

Bases: Beacon

moduleInventorySize = 1
distributionEffectivity = 1
__init__(speed=0, productivity=0, energy=0, pollution=0)
useSpeedBeacons(machine, beacon, *, num=1, max=(1, 0), roundUp=False, stripExisting=True)

Add enough speed beacons to reduce the number of machines needed to num.

If max is specified use up to that number of beacons. If more beacons are needed, increase the number of machines so that no more than max beacons are used per machine.

useEffectivityBeacons(machine, beacon, roundUp=False)

Add enough effectivity beacons to reduce the energy consumption to the limit of -80%.

useBeacons(machine, speedBeacon=None, effectivityBeacon=None, *, roundUp=False, stripExisting=True)

Add enough speed beacons to reduce the number of machines needed to one and then enough effectivity beacons to bring the energy consumption to the limit of -80%.

setGameConfig

setGameConfig(mode, path=None, includeDisabled=True)

Changes the game configuration.

mode

One of: 'normal' for normal gameplay; 'expansive' for the expensive gameplay mode; 'custom' for vanilla gameplay but using a custom configuration; 'mod' for overhaul mods; or a string specifying a custom mod with builtin support. See the mods module for currently supported mods.

path

Path to a JSON file created by the Recipe Exporter mod. Ignored if mode is 'normal' or 'expensive', otherwise it must be provided.

includeDisabled

If false, skip recipes marked as disabled. Disabled recipes include those that are not yet researched.

Note that changing the game configuration creates a new set of symbols in the itm, rcp, mch, and presets modules. Any non-symbolic references to symboles created before calling this function are unlikely to work.

The game configuration is stored in a context varable config.gameInfo to make it possible to use different game configurations within the same python program.

Returns a contextvars.Token that can be used to restore the previous configuration.

userRecipesFile()

Attempt to determine the location of the JSON file created by the “Recipe Exporter” mod.

mods module

Support for specific mods.

Each mod is it’s own function. To use just specify the name as the first paramater to setGameConfig. setGameConfig convertes the name to lowercase and transforms - and spaces to _. So for example to use support for Krastorio 2 you can use any of Krastorio 2, krastorio 2, or krastorio_2.

krastorio_2(gameInfo, **kwargs)

Support for the “Krastorio 2” mod.

Removes the kr- prefix from internal names when converting them to alises. Also, loader, fast_loader, and express_loader refer to the Krastorio 2 versions and not the builtin versions.

produce will still work in some cases, but special support for Krastorio 2 specific recipes has not yet been added.

presets.MP_EARLY_GAME, presets.MP_LATE_GAME, presets.MP_MAX_PROD, and presets.SPEED_BEACON are provided. In addition presets.MP_MID_LATE_GAME is provided for use before the three advanced versions of machines beacome available, and presets.SPEED_BEACON_2 is provided as a shortcut for mch.SingularityBeacon(modules=2*itm.speed_module_3).

space_exploration(gameInfo, **kwargs)

Support for the “Space Exploration” mod.

Removes the se- prefix from internal names when converting them to alises.

Due to complexity of Space Exploration produce, as it is currently written is unlikely to ever work well. See Unbounded Throttles in the overview guide.

sek2(gameInfo, **kwargs)

Support for Space Exploration + Krastorio 2

Removes both the kr- and se- prefixes except for the antimatter reactors and fuel refineries as a version exists in both mods. The loader for the space transport belt aliases to space_loader.

Miscellaneous

These symbols are not imported by from factorocalc import *.

class Constraint

Bases: object

__slots__ = ()
class Term(arg)

Bases: tuple

property num
property item
static __new__(cls, arg)
__repr__()

Return repr(self).

__str__()

Return str(self).

machine module

Base classes for machines in mch. Do not use directly.

class Category(name, members)

Bases: Immutable

__init__(name, members)
__repr__()

Return repr(self).

class BurnerMixin(*args, fuel=None, **kws)

Bases: object

energyType = 'burner'
__init__(*args, fuel=None, **kws)
fuel: Item = None
__setattr__(prop, val)

Implement setattr(self, name, value).

__eq__(other)

Return self==value.

__hash__ = None
__match_args__ = ('fuel',)
class ElectricMixin

Bases: object

energyType = 'electric'
__eq__(other)

Return self==value.

__hash__ = None
__match_args__ = ()
class ModulesMixin(*args, modules=None, beacons=None, beacon=None, **kws)

Bases: _ModulesHelperMixin

__init__(*args, modules=None, beacons=None, beacon=None, **kws)

Set modules and beacons for a machine.

modules can either be a list of modules or a single module to fill the machine with the maxium amount of the given module.

When setting beacons the special string counter can be used to create a FakeBeacon that will counter the negative effects of any modules present.

modules: tuple[Module, ...]
beacons: tuple
__setattr__(prop, val)

Implement setattr(self, name, value).

bonus()
__eq__(other)

Return self==value.

__hash__ = None
__match_args__ = ('modules', 'beacons')
class Beacon(*args, id=None, modules=None, freeze=True, **kws)

Bases: _ModulesHelperMixin, Machine

name = 'beacon'
width = 3
height = 3
moduleInventorySize = (1, 0)
distributionEffectivity = (1, 2)
supplyAreaDistance = 3
__init__(*args, id=None, modules=None, freeze=True, **kws)
id: str
modules: tuple[Module, ...]
__setattr__(prop, val)

Implement setattr(self, name, value).

__delattr__(prop)

Implement delattr(self, name).

__hash__()

Return hash(self).

effect()
__eq__(other)

Return self==value.

__match_args__ = ('throttle', 'unbounded', 'blueprintInfo', '_Machine__flows1', '_Machine__flows', 'id', 'modules', '_frozen')
class UnresolvedBeacon(id)

Bases: object

__slots__ = 'id'
__init__(id)
id
class Boiler(*args, **kwargs)

Bases: BurnerMixin, CraftingMachine

name = 'boiler'
baseEnergyUsage = 1800000
energyDrain = 0
pollution = 30
__init__(**kws)
class AssemblingMachine(*args, **kwargs)

Bases: CraftingMachine

class Furnace(*args, **kwargs)

Bases: CraftingMachine

class RocketSilo(*args, **kwargs)

Bases: CraftingMachine

__eq__(other)

Return self==value.

__hash__ = None
__match_args__ = ('throttle', 'unbounded', 'blueprintInfo', '_Machine__flows1', '_Machine__flows', 'recipe')
class Recipe(name, category, origRecipe, inputs, products, byproducts, time, order, cargo)

Bases: Recipe

origRecipe
cargo
__slots__ = ('origRecipe', 'cargo')
__init__(name, category, origRecipe, inputs, products, byproducts, time, order, cargo)
delay = (811, 20)
classmethod defaultProduct()

setGameConfig internals

These symbols are only useful when adding support for new mods and are not imported by from factorocalc import *.

importGameInfo(gameInfo, *, includeDisabled=True, preAliasPasses=(), nameTouchups=None, presets=None, extraPasses=(), craftingHints=None, byproducts=('empty-barrel',), rocketRecipeHints=None, logger=None)

Import game info by populating the config.gameInfo context variable.

gameInfo

A JSON string or pathlib.Path to a file that contains the game info to import. Created with the “Recipe Exporter” mod.

includeDisabled

If false, skip recipes marked as disabled. Disabled recipes include those that are not yet researched.

nameTouchups

A function to transform internal names before they are converted to aliases.

presets

A function to create useful presets that live in the presets module. The function takes no paramaters and is expected to return a dict. The config.gameInfo context variable is set so mch, itm, rcp are now populated.

extraPasses

Sequence of extra passes to run. Each function takes in config.gameInfo as a paramater and is expected to modify it in place.

craftingHints

A function to create hints used to guide the selection of machines produce selects. Like the presets function, it takes no paramaters and is expected to return a dict. See the source code for vanillaCraftingHints for more details on how this function is used.

byproducts

A list used to help determine byproducts in recipes that have more than one output. Each element of the list is one of: an internal name of an item, a tuple with multiple items, or a nested tuple of the form (<item>, (<item>, ...))`.

If just an item name, than that item is considered a byproduct if a recipe has multiple outputs and at least one other output is not in the list.

If a tuple, and more than one item within the tuple is in the output of a recipe, the earlier item will be considered a byproduct and the later item the normal output. For example, the tuple ('empty-barrel', 'water') will mark both the empty barrel and water as a byproduct, but if both are outputs of a recipe (for example when emptying a water barrel) than the empty barrel will be the byproduct.

A tuple of the form (<item>, (<item1>, <item2>, ...)). Is a shortcut for (<item>, <item1>), (<item>, <item2>), (<item>, ...).

Within a tuple, the special string *fluid* can be used as shortcut for all possible fluids in the game. Unlike specifying the fluids explicitly, the fluid itself is not marked as a byproduct, unless it is also mentioned elsewhere is the list. For example, [('empty-barrel', 'water')] is equivalent to [('empty-barrel', '*fluid*'), 'water'].

rocketRecipeHints

A mapping used to guide the creation of special recipes for the results of a rocket launch. The key is normaly a string of the form <rocket-silo>::<product>, where <rocket-silo> is the internal name of the rocket silo used to launch the rocket, and <product> is the result of launching the rocket. The value of the mapping is one of '' (an empty string), default, default-for-machine, default-for-item or skip. If an empty string or default-for-machine than a recipe is created but the name is mangled. If default or default-for-item, than a recipe is created and given the same name as the product. In addition, if the value is default or default-for-machine than the recipe will be assumed to be the product of a launching a rocket in the specified rocket silo when importing blueprints. If skip is used than no recipe is created. As a special case, if skip is used and the key is a name of a rocket silo without any product, than no recipes are created involving that rocket silo.

If logger is set then a warning will be created for any combinations not included in this mapping.

logger

Function called to log additional info, it is called once per line to be logged. A suitable function to use, for example, would be print.

genMaxProd(maxLevel, *machines)
vanillaResearchHacks(gi)
vanillaCraftingHints()
class CraftingHint(also: 'list' = <factory>, priority: 'int' = 0, boxPriority: 'int' = 0)

Bases: object

also: list
priority: int = 0
boxPriority: int = 0
__eq__(other)

Return self==value.

__hash__ = None
__init__(also: list = <factory>, priority: int = 0, boxPriority: int = 0) None
__match_args__ = ('also', 'priority', 'boxPriority')
__repr__()

Return repr(self).

class GameInfo(rcp: 'Objs' = <factory>, rcpByName: 'dict' = None, itm: 'Objs' = <factory>, itmByName: 'dict' = None, mch: 'Objs' = <factory>, mchByName: 'dict' = None, presets: 'dict' = None, recipesThatMake: 'dict' = None, recipesThatUse: 'dict' = None, craftingHints: 'dict' = None, rocketSiloDefaultProduct: 'dict' = <factory>, translatedNames: 'dict' = None, aliases: 'dict' = <factory>, disabledRecipes: 'set' = <factory>, modules: 'Modules' = <factory>)

Bases: object

rcp: Objs
rcpByName: dict = None
itm: Objs
itmByName: dict = None
mch: Objs
mchByName: dict = None
presets: dict = None
recipesThatMake: dict = None
recipesThatUse: dict = None
craftingHints: dict = None
rocketSiloDefaultProduct: dict
translatedNames: dict = None
aliases: dict
disabledRecipes: set
class Modules(speed: 'dict' = <factory>, productivity: 'dict' = <factory>, effectivity: 'dict' = <factory>, other: 'dict' = <factory>)

Bases: object

class List(iterable=(), /)

Bases: list

__slots__ = 'best'
best
speed: dict
productivity: dict
effectivity: dict
other: dict
__eq__(other)

Return self==value.

__hash__ = None
__init__(speed: dict = <factory>, productivity: dict = <factory>, effectivity: dict = <factory>, other: dict = <factory>) None
__match_args__ = ('speed', 'productivity', 'effectivity', 'other')
__repr__()

Return repr(self).

modules: Modules
finalize()
__eq__(other)

Return self==value.

__hash__ = None
__init__(rcp: Objs = <factory>, rcpByName: dict = None, itm: Objs = <factory>, itmByName: dict = None, mch: Objs = <factory>, mchByName: dict = None, presets: dict = None, recipesThatMake: dict = None, recipesThatUse: dict = None, craftingHints: dict = None, rocketSiloDefaultProduct: dict = <factory>, translatedNames: dict = None, aliases: dict = <factory>, disabledRecipes: set = <factory>, modules: Modules = <factory>) None
__match_args__ = ('rcp', 'rcpByName', 'itm', 'itmByName', 'mch', 'mchByName', 'presets', 'recipesThatMake', 'recipesThatUse', 'craftingHints', 'rocketSiloDefaultProduct', 'translatedNames', 'aliases', 'disabledRecipes', 'modules')
__repr__()

Return repr(self).

toPythonName(name)

Convert all - to _

toClassName(name)

Convert name to title case.

fracs module

Fractions with less overhead.

class Frac(num, den)

Bases: tuple, Rational

Streamlined fraction implementation.

Frac is similar to fractions.Fraction except with less overhead. In the general case the speedup is around 2. When mixing fractions with integers, and especially with special values (i.e. 0, 1 and -1), the speedup is significantly higher. Frac differs in several ways from Fraction and therefore is not intended to be used as a drop in replacement.

Unlike Fraction, Frac does not freely mix with floats. For this reason it is not a numbers.Rational.

Frac operators will return an int if the denominator is 1. For this reason, Frac’s shoud be created with the frac or div function. Also, to avoid unexpected floats the division operator is not supported and instead the previous mentioned div function should be used.

Infinity and NaN is supported. NaN is a special type with a single value. So to test for NaN, it is acceptable to use x is NaN.

hash(Frac) is supported, but for speed it is only compatible with itself. The automatic conversion to integers means that hash(frac(2)) == hash(2). However, hash(frac(1,2)) != hash(0.5) and hash(frac(1,2)) != hash(fractions.Fraction(1,2))

Compression operations will return Invalid if either argument is a NaN. Attempting to convert Invalid to a bool will raise a ValueError. This prevents accidental comparasion with NaN and allows NaN to be used as an unknown in a limited sense. If you want the traditional behavior use (x == y) is True. If you want NaN to represent an unknown use (x == y) is not False.

To minimize overhead, Frac is implemented as a tuple, but this should be considered an implemenation detail.

Frac defines numerator and denominator and uses duck typing so it will accept a Fraction in operators but will not automatically convert to a Fraction.

Format specifiers are also supported. If the type character is empty it will be formated as <num>/<den> otherwise it will be converted to a Decimal and then formatted. Trailing zeros are significant when the type character is ‘g’. For example, ‘1.500’ represents a fraction close to 3/2 while ‘1.5’ represents the exact fraction 3/2.

__slots__ = ()
static __new__(cls, num, den)

construct Frac directly, prefer frac function instead

property numerator
property denominator
__eq__(other)

Return self==value.

__ne__(other)

Return self!=value.

__lt__(other)

Return self<value.

__le__(other)

Return self<=value.

__gt__(other)

Return self>value.

__ge__(other)

Return self>=value.

__hash__()

Return hash(self).

as_str(sign='')
__str__(sign='')

Return str(self).

__repr__()

Return repr(self).

__format__(spec)

Default object formatter.

__pos__()
__neg__()
__abs__()
__trunc__()
__ceil__()
__floor__()
__float__()
__add__(other)

Return self+value.

__radd__(other)

Return self+value.

__sub__(other)
__rsub__(other)
__mul__(other)

Return self*value.

__rmul__(other)

Return value*self.

__truediv__(other)

unimplemented, use div function instead

__rtruediv__(other)

unimplemented, use div function instead

__copy__()
__deepcopy__(_)
frac(num=0, den=None, *, float_conv_method='if int')

return a fraction that automatically convertes to an int when applicable

Parameters:
  • num – a number of any type or string, the string may be an int, decimal, or a fraction of the form ‘num/den’.

  • den – denominator of fraction, may be an int or Frac. If defined num must also be an int or Frac.

  • float_conv_method – one of disallow, if int, exact, or round

Returns:

Frac or an int

div(num, den)

equivalent to num/den but returns a Frac or int instead of a float.

Inf: Frac
NaN: NanType
Invalid: InvalidType
frac_from_float_exact(other)
frac_from_float_round(other, precision=15)
as_integer_ratio(num)
trunc = <built-in function trunc>
ceil = <built-in function ceil>
floor = <built-in function floor>
isfinite(num)
isinf(num)
isnan(num)
assume_positive_zero = <ContextVar name='fracs.assume_positive_zero' default=False at 0x7fd0f76c99e0>
allow_nans = <ContextVar name='fracs.assume_positive_zero' default=False at 0x7fd0f76c9b20>
class Rational

Bases: Number

Abstract base class that includes int and Frac.

Differes from numbers.Rational in that it is not also a numbers.Real.

To avoid confusion with numbers.Rational, it is not exported by default.

__slots__ = ()

solver module

Solver intervals.

Example:

>>> from factoriocalc import *
>>> config.machinePrefs.set(MP_MAX_PROD.withSpeedBeacons({AssemblingMachine3:8, ChemicalPlant:8, OilRefinery:12}))
>>> rocketFuel = UnboundedBox(1*rcp.advanced_oil_processing()
                              + 1*rcp.heavy_oil_cracking()
                              + 1*rcp.light_oil_cracking()
                              + 1*rcp.solid_fuel_from_light_oil()
                              + 1*rcp.solid_fuel_from_petroleum_gas()
                              + 1*rcp.rocket_fuel(),
                              outputs = [itm.rocket_fuel@6])
>>> solver = rocketFuel.solver()
>>> solver.reset()
<SolveRes.UNSOLVED: -2>
>>> solver.print()
+113.258*light-oil-cracking-m -45.5*solid-fuel-from-petroleum-gas-m +18.0360*solid-fuel-from-light-oil-m +1.45345*rocket-fuel-m = 0 (140251354372976-petroleum-gas)
+2.9575*solid-fuel-from-light-oil-m +2.9575*solid-fuel-from-petroleum-gas-m -1.83333*rocket-fuel-m = 0 (140251354372976-solid-fuel)
+0.256667*rocket-fuel-m = 6 (140251354372976-rocket-fuel)
advanced-oil-processing-m = +0.577677*light-oil-cracking-m +0.192559*solid-fuel-from-light-oil-m +0.0155176*rocket-fuel-m
heavy-oil-cracking-m = +0.270270*light-oil-cracking-m +0.0900901*solid-fuel-from-light-oil-m +0.00726001*rocket-fuel-m
max (inputs): -200.209*light-oil-cracking-m -43.9865*solid-fuel-from-light-oil-m -3.54470*rocket-fuel-m
  aux (water): -124.534*light-oil-cracking-m -18.7613*solid-fuel-from-light-oil-m -1.51190*rocket-fuel-m
  aux (crude-oil): -75.6757*light-oil-cracking-m -25.2252*solid-fuel-from-light-oil-m -2.03280*rocket-fuel-m
>>> solver.tableau.print()
      -0-    -1-    -2-    -3-   -4-  -5-  -6-
    light- solid- solid- rocket  a0   a1   p2  |    rhs
 0:  0.635 -0.255  0.101  0.008  *1*   0    0  |     0     | -4- a0
 1:    0    0.381  0.381 -0.236   0   *1*   0  |     0     | -5- a1
 2:    0      0      0      1     0    0   *1* |  23.3766  | -6- p2

 3: -0.635 -0.126 -0.482  0.228   0    0    0  |     0     | max
 4:    0      0      0     -1     0    0    0  | -23.3766  | max
>>> solver.tableau.solve(zero=True)
<SolveRes.OPTIMAL: 1>
>>> solver.tableau.solve(zero=True)
<SolveRes.OPTIMAL: 1>
>>> solver.tableau.addPendingObjective()
>>> solver.tableau.print()
      -0-    -1-    -2-    -3-
    light- solid- solid- rocket |    rhs
 0:   *1*     0    0.560    0   |  5.52158  | -0- light-oil-cracking-m
 1:    0     *1*     1      0   |  14.4910  | -1- solid-fuel-from-petroleum-gas-m
 2:    0      0      0     *1*  |  23.3766  | -3- rocket-fuel-m

 3:    0      0   -68.32    0   | -1188.34  | max (inputs)
 4:    0      0   -51.10    0   | -722.966  | aux (water)
 5:    0      0   -17.22    0   | -465.369  | aux (crude-oil)
>>> solver.tableau.solve()
<SolveRes.UNIQUE: 2>
>>> solver.tableau.print()
      -0-    -1-    -2-    -3-
    light- solid- solid- rocket |    rhs
 0:  1.782    0     *1*     0   |  9.84266  | -2- solid-fuel-from-light-oil-m
 1: -1.782   *1*     0      0   |  4.64834  | -1- solid-fuel-from-petroleum-gas-m
 2:    0      0      0     *1*  |  23.3766  | -3- rocket-fuel-m

 3:  121.8    0      0      0   | -515.807  | max (inputs)
 4:  91.09    0      0      0   | -220.004  | aux (water)
 5:  30.70    0      0      0   | -295.803  | aux (crude-oil)
>>> solver.tableau.solution().print()
Solution:
  light-oil-cracking-m = 0
  solid-fuel-from-petroleum-gas-m = 4.64833996
  solid-fuel-from-light-oil-m = 9.84266354
  rocket-fuel-m = 23.3766234
Other:
class Var(id, name=None, max=1)

Bases: object

__slots__ = ('id', 'name', 'max')
__init__(id, name=None, max=1)
id
name
max
__eq__(other)

Return self==value.

__hash__()

Return hash(self).

__str__()

Return str(self).

__repr__()

Return repr(self).

class Term(var, rate)

Bases: tuple

__slots__ = ()
property var
property rate
static __new__(cls, *args)
__str__()

Return str(self).

__repr__()

Return repr(self).

class SolveRes(value)

Bases: OrdEnum

Result of solving a linear equation system.

The values of the enum are subject to change, but the relative order should be stable.

UNSOLVED = -2

not yet solved

NOOP = -1

already solved

OPTIMAL = 1

a solution was found, no test for uniqueness was done

UNIQUE = 2

all output machines are at there maxium giving the constraints

MULTI = 3

output machines are at there maxium giving the constraints but there are multiple possible configurations

OK = 4

a solution was found but some machines are not at there maxium output, to make the solution unique add additional constraints or priorities

PARTIAL = 5

a partial solution was found by removing constraints

UNBOUNDED = 6

the system is unbounded, a partial solution was found by setting unbounded vars to 0

ok()
notok()
failed()
class Cond(order, symbol, fun)

Bases: NamedTuple

order: int

Alias for field number 0

symbol: str

Alias for field number 1

fun: Callable[[Rational, Rational], bool]

Alias for field number 2

__call__(x, y=0)

Call self as a function.

__repr__()

Return repr(self).

__eq__(other)

Return self==value.

__ne__(other)

Return self!=value.

__copy__()
__deepcopy__(memo)
NONE = (5, '?', None)
__match_args__ = ('order', 'symbol', 'fun')
static __new__(_cls, order: int, symbol: str, fun: Callable[[Rational, Rational], bool])

Create new instance of Cond(order, symbol, fun)

__orig_bases__ = (<function NamedTuple>,)
__slots__ = ()
EQ = <Cond "=">
GE = <Cond ">=">
LE = <Cond "<=">
class LinearEqId(boxid, item, qualifier)

Bases: NamedTuple

boxid: int

Alias for field number 0

item: Var | Ingredient

Alias for field number 1

qualifier: str

Alias for field number 2

__str__()

Return str(self).

__repr__()

Return repr(self).

__match_args__ = ('boxid', 'item', 'qualifier')
static __new__(_cls, boxid: int, item: Var | Ingredient, qualifier: str = '')

Create new instance of LinearEqId(boxid, item, qualifier)

__orig_bases__ = (<function NamedTuple>,)
__slots__ = ()
class Terms(terms=())

Bases: dict

__init__(terms=())
__getitem__()

x.__getitem__(y) <==> x[y]

asSeq()
add(var, rate)
merge(other, mul=1)
apply(values=None)
sub(var, repl)
subAll(repl)
neg()
__str__()

Return str(self).

__iadd__(other, mul=1)
__isub__(other, *, mul=-1)
__imul__(other)
__itruediv__(other)
__eq__(other)

Return self==value.

__hash__ = None
__match_args__ = ()
__repr__()

Return repr(self).

class LinearEq(id: 'LinearEqId', terms: 'tuple', cond: 'Cond' = None, rate: 'Rational' = None)

Bases: object

id: LinearEqId
terms: tuple
cond: Cond = None
rate: Rational = None
__post_init__()
flow(solution, default=(1, 0))
solved(solution, default=(1, 0))
__str__()

Return str(self).

sympify()
__delattr__(name)

Implement delattr(self, name).

__eq__(other)

Return self==value.

__hash__()

Return hash(self).

__init__(id: LinearEqId, terms: tuple, cond: Cond = None, rate: Rational = None) None
__match_args__ = ('id', 'terms', 'cond', 'rate')
__repr__()

Return repr(self).

__setattr__(name, value)

Implement setattr(self, name, value).

class VarGroup(*args, **kwargs)

Bases: Group

__init__(var)
class LinearEqSystem

Bases: object

print(out=None, prefix='')
classmethod fromBox(box, *, _tally=None)
__imul__(num)
external()
sympify()
solver()
class Solver(leqs)

Bases: object

__init__(leqs)
reset(simplify=True)

Reset the state and does preliminary work for solving.

Called automatically by solve(). But can be called manually to get access to the underlying tableau.

prep(simplify=True)

Reset the state and does preliminary work for solving.

Called automatically by solve(). But can be called manually to get access to the underlying tableau.

print(out=None)
solve()

Solve the linear equation system.

solution()

Return the solution to the solved linear equation.

Return a tuple pair. The first component is a SolveRes. The second component is a dict with the solution to the system.

apply()

Apply the solution the the underlying box.

Returns the same value as solution().

class SlackVar(rowIdx: 'int')

Bases: object

__slots__ = 'rowIdx'
rowIdx: int
__str__()

Return str(self).

__delattr__(name)

Implement delattr(self, name).

__eq__(other)

Return self==value.

__hash__()

Return hash(self).

__init__(rowIdx: int) None
__match_args__ = ('rowIdx',)
__repr__()

Return repr(self).

__setattr__(name, value)

Implement setattr(self, name, value).

class ArtificialVar(rowIdx: 'int')

Bases: object

__slots__ = 'rowIdx'
rowIdx: int
__str__()

Return str(self).

__delattr__(name)

Implement delattr(self, name).

__eq__(other)

Return self==value.

__hash__()

Return hash(self).

__init__(rowIdx: int) None
__match_args__ = ('rowIdx',)
__repr__()

Return repr(self).

__setattr__(name, value)

Implement setattr(self, name, value).

class PartialVar(rowIdx: 'int')

Bases: ArtificialVar

__slots__ = ()
__str__()

Return str(self).

__delattr__(name)

Implement delattr(self, name).

__eq__(other)

Return self==value.

__hash__()

Return hash(self).

__init__(rowIdx: int) None
__match_args__ = ('rowIdx',)
__repr__()

Return repr(self).

__setattr__(name, value)

Implement setattr(self, name, value).

class OptFun(terms, note)

Bases: NamedTuple

terms: Any

Alias for field number 0

note: Any

Alias for field number 1

__match_args__ = ('terms', 'note')
static __new__(_cls, terms: Any, note: Any = None)

Create new instance of OptFun(terms, note)

__orig_bases__ = (<function NamedTuple>,)
__repr__()

Return a nicely formatted representation string

__slots__ = ()
class Tableau(eqs, objectives)

Bases: object

__init__(eqs, objectives)
print(out=None, ratioCol=None)
normalize(rowIdx, colIdx)
clear(rowIdx, colIdx)
fixClearedCol(rowIdx, colIdx, rowIdxToFix)
clearCol(colIdx)
zeroCol(colIdx)
solution()
allSolutions()
ratios(colIdx)
bestRow(colIdx, start=0)
cleared()
encoding()
addObjective(terms, note=None, label='max')
max(rowIdx)
solve(rowIdx=None, *, zero=False)
addPendingObjective()
solveAll()
class Solution(solution, other)

Bases: NamedTuple

solution: dict

Alias for field number 0

other: dict

Alias for field number 1

print(out=None)
__match_args__ = ('solution', 'other')
static __new__(_cls, solution: dict, other: dict)

Create new instance of Solution(solution, other)

__orig_bases__ = (<function NamedTuple>,)
__repr__()

Return a nicely formatted representation string

__slots__ = ()