# Boat Rental

The following problem was posed as the DMCommunity September 2024 challenge.

Rental Boats

Floataway tours has $420,000 that may be used to purchase new rental boats for hire during the summer. The boats can be purchased from two different manufacturers. Floataway tours would like to purchase at least 50 boats and would like to purchase the same number from Sleekboat as from Racer to maintain goodwill. Also, Floataway Tours wishes to have a total capacity of at least 200. Data about the boats is summarized below:

Boat Manufacturer Cost Seating Expected Daily Profit Speedhawk Sleekboat 6000 3 70 Silverbird Sleekboat 7000 5 80 Catman Racer 5000 2 50 Classy Racer 9000 6 110

Can we solve this using cDMN? Let’s find out.

As always, we want to start by creating a glossary (See 3.1 Glossary). For this challenge, we can clearly identify two types: boats, and their manufacturer.

Type | ||
---|---|---|

Name | Type | Values |

Boat | String | Speedhawk, Silverbird, Catman, Classy |

Manufacturer | String | Sleekboat, Racer |

We’ve also been given some information about the boats that we need to be able to represent: their manufacturer, their cost, their seating capacity, and their estimated profit. These properties are best represented using a function, i.e., a mapping from one type on another.

Additionally, we also want a way to represent the number of each boat type that we buy, and the total of each boat type bought per manufacturer.

Function | |
---|---|

Name | Type |

manufacturer of Boat | Manufacturer |

cost of Boat | Int |

seating of Boat | Int |

profit of Boat | Int |

nb of Boat | Int |

total of Manufacturer | Int |

Finally, we need a way to represent the three requirements (total boats, total capacity, total price) and a way to represent the total profit. As these are just numerical values, we can represent them as constant variables. Note that constant here does not mean that their value always needs to be known up front, but rather that they have exactly one value in each solution.

Constant | |
---|---|

Name | Type |

total boats | Int |

total capacity | Int |

total price | Int |

total profit | Int |

That concludes our glossary! We know have all the symbols that we need to start expressing rules. The first piece of logic that we’ll add is quite a simple one: we can only buy a positive number of boats. Because our function nb of Boat maps each boat on an integer number, it would be possible to have negative boats without such a constraint.

Non-neg constraint | ||
---|---|---|

E* | Boat | nb of Boat |

1 | - | ≥ |

This table can be read as “The number of each boat should be greater than or equal to zero”.

Next, we add the constraints on the total requirements:

minimum capacity of 200

at least 50 boats

max total price of 420000

total Sleekboat is equal to total Racer

Starting value | ||||
---|---|---|---|---|

E* | total capacity | total boats | total price | total of Sleekboat |

1 | ≥ 200 | ≥ 50 | ≤ 420000 | total of Racer |

Of course, we still need to define how we calculate these values. The total profit, capacity and price are luckily quite easy to calculate using a C+ (count) table, as we just need to multiply the property of each boat with the number bought of each boat. Even better, we can count all three of them together in the same table.

Count parameters | ||||
---|---|---|---|---|

C+ | Boat | total profit | total capacity | total price |

1 | - | profit of Boat * nb of Boat | seating of Boat * nb of Boat | cost of Boat * nb of Boat |

Additionally, we also need to calculate the number of boats per manufacturer. This table is similar to the previous one, but we will also need to “go over” (= quantify) each manufacturer as well.

Calculate number per manufacturer | |||
---|---|---|---|

C+ | Boat | Manufacturer | total of Manufacturer |

1 | - | manufacturer of Boat | nb of Boat |

In essence, this table will, for each manufacturer, count their number of boats. Note that the cell manufacturer of Boat is crucial here, as this one ensures that only the boats by that manufacturer are counted.

And that’s basically it for the business logic! All in all not that difficult. All that remains is specifying the concrete boat data using a data table, and adding a goal table to express the optimization.

Boat info | |||||
---|---|---|---|---|---|

D | Boat | manufacturer of Boat | cost of Boat | seating of Boat | profit of Boat |

1 | Speedhawk | Sleekboat | 6000 | 3 | 70 |

2 | Silverbird | Sleekboat | 7000 | 5 | 80 |

3 | Catman | Racer | 5000 | 2 | 50 |

4 | Classy | Racer | 9000 | 6 | 110 |

Goal |
---|

Maximize total profit |

We can now run our model using the cDMN solver or the online IDE. This results in the following output:

```
Model 1
==========
nb_of_Boat := {Speedhawk -> 28, Silverbird -> 0, Catman -> 0, Classy -> 28}.
total_of_Manufacturer := {Sleekboat -> 28, Racer -> 28}.
total_boats := 50.
total_capacity := 252.
total_price := 420000.
total_profit := 5040.
Elapsed Time:
0.499
```

The optimal distribution is to buy 28 Speedhawk en 28 Classy, for a total estimated profit of 5040 dollar.