language Essence 1.3

$ Problem Tank Allocation
$ Problem details available at
$ Essence model by Andrew Martin
$ Licenced under CC-BY-4.0 :

$ rather than tracking invividual volumes in each tank,
$ sum all available volume available
$ this must be >= the volume to ship
$ this prevents solver checking every permutaion with
$ the same tank allocation but different levels

$ letting numCargos be 1 currently breaks savillerow when parsing incompatabilities
$ constraining to >=2
given numCargos : int(2..)

given numTanks : int(1..)

letting dCargos be domain int(1..numCargos)
letting dAllCargos be domain int(0..numCargos)
letting dTanks be domain int(1..numTanks)

given capacities : matrix indexed by [dTanks] of int(1..)

given neighbours : matrix indexed by [dTanks] of set of dTanks

given impossibleCargos : matrix indexed by [dTanks] of set of dAllCargos

given volumeToShip : matrix indexed by [dCargos] of int(1..)

given incompatibilities : set of set (size 2) of dCargos

$ a tank can contain one cargo type or it can be empty (cargo 0)
find allocation : matrix indexed by [dTanks] of dAllCargos

$ maximising number of empty tanks
maximising (sum tank : dTanks . toInt(allocation[tank] = 0))

such that

    $ volumeToShip of cargo X <= amount of cargo X included in allocation
    forAll cargo : dCargos .
        (sum tank : dTanks . capacities[tank] * toInt(allocation[tank] = cargo) ) >= volumeToShip[cargo]

such that

    $ no tank can be allocated a cargo in its impossibleCargos
    forAll tank : dTanks .
        !(allocation[tank] in impossibleCargos[tank])


    $ no tank can be neigbors with a tank containing incompatible cargo
        forAll neighbour in neighbours[tank] .
            !({allocation[tank], allocation[neighbour]} in incompatibilities)