timefold-solver
timefold-solver copied to clipboard
HardMediumSoftMicrosScore
Motivation:
In use cases with a fairness or load balancing constraint, alongside other soft constraints, the only practical way to write that constraint is using the sqrt(sum(x²)) pattern. In the tennis example there's a loadBalance() function that does that for you.
This sqrt() gives a decimal number and that does not work well with LongScore:
- BigDecimalScore is slow and a bit of a pain
- Only the first 4 decimals matter (simple math support that this accuracy is accurate enough). So typically it is mulitplied by 1 milliion and put into a LongScore. The 6 digits (micros) are 2 digits for safety.
However, this is a pain:
- for clarity (think logs etc)
- for visualization in any UI (including score analysis etc)
- for score weights
Proposal A
A new score: HardMediumSoftMicrosScore. It uses long underneath.
- long hardMicros
- long mediumMicros
- long softMicros
- toString() = hardMicros / 1M + (hardMicros % 1M == 0 ? "" : hardMicros % 1M ...
- ONE_SOFT => softMicros = 1_000_000
- ofSoft(7) => softMicros = 7_000_000
- ofSoftMicros(7) => softMicros = 7
The score weight of the dayOffRequest constraint is ofSoft(10).
Is the score weight of the fairness constraint is ofSoftMicros(1)?
- A1) Yes. But that's confusing for users to tune.
- A2) No, it's ofSoft(1) and the constraint impl does a trick so the accuracy isn't lost.
Related design
- [ ] Standarize and document
loadBalance()of the tennis example - [ ] Guide for fairness and load balancing, including FTE (Full time equivelant) challenges
- [ ] An understandable version of math of https://www.optaplanner.org/blog/2017/02/03/FormulaForMeasuringUnfairness.html