You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
*`--switching-penalty`: Cost for driver swaps (positive disincentivizes switching)
20
+
*`--role-coupling-weight`: Incentive for role coupling (positive incentivizes coupling)
21
+
*`--rotation-beat-weight`: Penalty for fairness deviation (positive incentivizes adherence)
22
+
23
+
See [TOOLS.md](./TOOLS.md) for full usage.
24
+
13
25
## The Library
14
26
15
-
**JresSolver** is a C++ library designed to optimize endurance racing schedules. It uses the **HiGHS** Mixed Integer Programming (MIP) solver to assign drivers (and optional spotters) to race stints while satisfying constraints such as fuel usage, maximum drive times, minimum rest periods, and driver availability.
27
+
**JresSolver** is a C++ library designed to optimize endurance racing schedules. It uses the **HiGHS** Mixed Integer Programming (MIP) solver to assign drivers (and optional spotters) to race stints while satisfying constraints such as fuel usage, maximum drive times, minimum rest periods, and driver availability. The library utilizes a modular constraint architecture for flexibility and extensibility.
16
28
17
29
### Data Structures
18
30
19
31
The C-API uses the following structs to pass data to and from the solver.
20
32
21
33
#### Input Structures
22
34
23
-
`JresSolverInput` is the main input struct. It contains arrays of the other input structs.
35
+
`JresSolverInput` is the main input struct. It contains arrays of the other input structs and global constraints.
24
36
25
37
| Field | Type | Description |
26
38
| :--- | :--- | :--- |
39
+
|`consecutiveStints`|`int`| Hard constraint: Required number of consecutive stints a driver must perform (block size). |
40
+
|`minimumRestHours`|`int`| Hard constraint: Minimum contiguous rest time required once per race. <br> **Integrated Mode:** Applies to combined Driving and Spotting time. <br> **Sequential Mode:** Applies only to Driving. |
27
41
|`teamMembers`|`JresTeamMember*`| A pointer to an array of team members. |
28
42
|`teamMembers_len`|`int`| The number of team members. |
29
43
|`availability`|`JresMemberAvailability*`| A pointer to an array of availability information. |
@@ -38,8 +52,6 @@ The C-API uses the following structs to pass data to and from the solver.
38
52
|`name`|`const char*`| Unique identifier for the member. |
39
53
|`isDriver`|`int`|`1` if the member can drive, `0` otherwise. |
40
54
|`isSpotter`|`int`|`1` if the member can spot, `0` otherwise. |
41
-
|`maxStints`|`int`| Hard constraint: Maximum number of consecutive stints a member can perform. |
42
-
|`minimumRestHours`|`int`| Hard constraint: Minimum contiguous rest time required once per race. <br> **Integrated Mode:** Applies to combined Driving and Spotting time. <br> **Sequential Mode:** Applies only to Driving. |
43
55
|`tzOffset`|`double`| Timezone offset in hours from UTC. |
44
56
45
57
`JresStint`
@@ -78,6 +90,18 @@ These structs are used to represent the availability of team members.
78
90
|`teamMembers`|`JresTeamMember*`| A pointer to an array of team members, including their tzOffset. |
79
91
|`teamMembers_len`|`int`| The number of team members. |
80
92
93
+
`JresSolverOptions`
94
+
95
+
| Field | Type | Description |
96
+
| :--- | :--- | :--- |
97
+
|`timeLimit`|`int`| Maximum time in seconds to let the solver run. |
98
+
|`spotterMode`|`JresSpotterMode`| Type of spotter scheduling to use (`NONE`, `INTEGRATED`, `SEQUENTIAL`). |
99
+
|`allowNoSpotter`|`bool`| Allow stints to have no spotter assigned. |
100
+
|`optimalityGap`|`double`| Solver stops when the gap to optimal is less than this (e.g., `0.2`). |
101
+
|`switchingPenalty`|`double`| Penalty applied when switching drivers between stints (default: `0.0`). |
102
+
|`roleCouplingWeight`|`double`| Weight for coupling driver and spotter roles (default: `0.0`). |
103
+
|`rotationBeatWeight`|`double`| Weight for adhering to a rotation beat or fairness metric (default: `0.0`). |
@@ -140,6 +165,14 @@ Mixed Integer Programming problems like race scheduling are NP-hard. The solver
140
165
141
166
The solver prioritizes hard constraints (rest times, fuel, availability) first. The optimality gap only affects soft preferences like minimizing consecutive stints. A 20% gap on these preferences is imperceptible in real-world use.
142
167
168
+
#### Switching Penalty
169
+
170
+
The `switchingPenalty` option adds a cost to the optimization objective every time the driver changes between two consecutive stints.
171
+
172
+
* **Goal**: To encourage the solver to keep the same driver in the car for multiple stints (e.g., doing a "double stint"), even if it's not strictly required by the `consecutiveStints` constraint.
173
+
* **Relationship to `consecutiveStints`**: `consecutiveStints` is a **hard constraint** (the solver *must* schedule blocks of this size). The `switchingPenalty` is a **soft incentive** that applies at the boundaries of these blocks to discourage swapping drivers even when a block ends.
174
+
* **Recommended Value**: Start with `10.0`. If the solver still switches drivers too often for your preference, increase it. If it starts violating preferred availability slots just to avoid a switch, decrease it.
175
+
143
176
-----
144
177
145
178
### JSON Helper Functions
@@ -160,6 +193,8 @@ The `raceDataJson` string passed to `jres_input_from_json` must strictly follow
160
193
161
194
| Field | Type | Required | Description |
162
195
| :--- | :--- | :--- | :--- |
196
+
| `consecutiveStints` | Integer | No (Default `1`) | Hard constraint: Required number of consecutive stints a driver must perform (block size). |
197
+
| `minimumRestHours` | Integer | No (Default `0`) | Hard constraint: Minimum contiguous rest time required once per race. <br> **Integrated Mode:** Applies to combined Driving and Spotting time. <br> **Sequential Mode:** Applies only to Driving. |
163
198
| `teamMembers` | Array | Yes | List of drivers and spotters (see below). |
164
199
| `availability` | Object | Yes | Map of availability constraints (see below). |
165
200
| `stints` | Array | Yes | List of pre-defined race stints (see below). |
@@ -179,8 +214,6 @@ The `raceDataJson` string passed to `jres_input_from_json` must strictly follow
179
214
| `name` | String | **Required** | Unique identifier for the member. |
180
215
| `isDriver` | Boolean | `true` | Can this member drive? |
181
216
| `isSpotter` | Boolean | `false` | Can this member spot? |
182
-
| `maxStints` | Integer| `1` | Hard constraint: Maximum number of consecutive stints a member can perform. |
183
-
| `minimumRestHours` | Integer| `0` | Hard constraint: Minimum contiguous rest time required once per race. <br> **Integrated Mode:** Applies to combined Driving and Spotting time. <br> **Sequential Mode:** Applies only to Driving. |
184
217
| `tzOffset` | Number | `0.0` | Timezone offset in hours from UTC. |
185
218
186
219
#### Availability Map & Time Formatting
@@ -203,13 +236,13 @@ The `availability` object maps a **Team Member's Name** to a dictionary of **Tim
0 commit comments