@@ -18,59 +18,61 @@ namespace jres::analysis {
1818
1919std::string explain_assignment_failure (
2020 int stintIndex,
21- const std::string& violationDriver ,
21+ jres::internal::ID violationDriverId ,
2222 const jres::internal::SolverInput& input,
2323 const std::vector<jres::internal::TeamMember>& driverPool,
24- const std::map<std::pair<std::string , int >, int >& driverWorkVars,
24+ const std::map<std::pair<jres::internal::ID , int >, int >& driverWorkVars,
2525 const std::vector<double >& colValues)
2626{
2727 using namespace jres ::internal;
2828 std::ostringstream ss;
2929
3030 // Time points for the target stint
31- auto tStart = TimeHelpers::stringToTimePoint ( input.stints [stintIndex].startTime ) ;
32- auto tEnd = TimeHelpers::stringToTimePoint ( input.stints [stintIndex].endTime ) ;
31+ auto tStart = input.stints [stintIndex].startTime ;
32+ auto tEnd = input.stints [stintIndex].endTime ;
3333
3434 // Identify which drivers are assigned to which stints in the CURRENT solution
35- std::map<std::string , std::set<int >> driverAssignments;
35+ std::map<ID , std::set<int >> driverAssignments;
3636 for (size_t s = 0 ; s < input.stints .size (); ++s) {
3737 for (const auto & p : driverPool) {
38- if (driverWorkVars.count ({p.name , (int )s})) {
39- int idx = driverWorkVars.at ({p.name , (int )s});
38+ if (driverWorkVars.count ({p.nameId , (int )s})) {
39+ int idx = driverWorkVars.at ({p.nameId , (int )s});
4040 if (idx < (int )colValues.size () && colValues[idx] > 0.5 ) {
41- driverAssignments[p.name ].insert ((int )s);
41+ driverAssignments[p.nameId ].insert ((int )s);
4242 }
4343 }
4444 }
4545 }
4646
4747 // Helper: Get stint duration in hours
4848 auto getDuration = [&](int sIdx ) {
49- auto s = TimeHelpers::stringToTimePoint (input.stints [sIdx ].startTime );
50- auto e = TimeHelpers::stringToTimePoint (input.stints [sIdx ].endTime );
51- return std::chrono::duration<double , std::ratio<3600 >>(e - s).count ();
49+ return std::difftime (input.stints [sIdx ].endTime , input.stints [sIdx ].startTime ) / 3600.0 ;
5250 };
5351
5452 ss << " Alternatives Analysis:" ;
5553
5654 for (const auto & candidate : driverPool) {
57- if (candidate.name == violationDriver ) continue ;
55+ if (candidate.nameId == violationDriverId ) continue ;
5856
59- ss << " \n - " << candidate.name << " : " ;
57+ std::string candidateName = input.strings .get_string (candidate.nameId );
58+
59+ ss << " \n - " << candidateName << " : " ;
6060 std::vector<std::string> reasons;
6161
6262 // Check Availability
6363 bool isUnavailable = false ;
64- auto it = input.availability .find (candidate.name );
64+ auto it = input.availability .find (candidate.nameId );
6565 if (it != input.availability .end ()) {
6666 auto cursor = tStart;
67+ // Align cursor to hour if not already (assuming availability is hourly)
68+ cursor = TimeHelpers::roundToHour (cursor);
69+
6770 while (cursor < tEnd) {
68- std::string key = TimeHelpers::timePointToKey (cursor);
69- if (it->second .count (key) && it->second .at (key) == Availability::Unavailable) {
71+ if (it->second .count (cursor) && it->second .at (cursor) == Availability::Unavailable) {
7072 isUnavailable = true ;
7173 break ;
7274 }
73- cursor += std::chrono::hours ( 1 ) ;
75+ cursor += 3600 ;
7476 }
7577 }
7678 if (isUnavailable) {
@@ -80,11 +82,11 @@ std::string explain_assignment_failure(
8082 // Check Consecutive Stints
8183 int consecutiveCount = 1 ;
8284 for (int k = stintIndex - 1 ; k >= 0 ; --k) {
83- if (driverAssignments[candidate.name ].count (k)) consecutiveCount++;
85+ if (driverAssignments[candidate.nameId ].count (k)) consecutiveCount++;
8486 else break ;
8587 }
8688 for (size_t k = stintIndex + 1 ; k < input.stints .size (); ++k) {
87- if (driverAssignments[candidate.name ].count ((int )k)) consecutiveCount++;
89+ if (driverAssignments[candidate.nameId ].count ((int )k)) consecutiveCount++;
8890 else break ;
8991 }
9092
@@ -95,15 +97,15 @@ std::string explain_assignment_failure(
9597 // Check Minimum Rest
9698 if (input.minimumRestHours > 0 ) {
9799 double minRestSec = input.minimumRestHours * 3600.0 ;
98- for (int assignedS : driverAssignments[candidate.name ]) {
99- auto s1_start = TimeHelpers::stringToTimePoint ( input.stints [stintIndex].startTime ) ;
100- auto s1_end = TimeHelpers::stringToTimePoint ( input.stints [stintIndex].endTime ) ;
101- auto s2_start = TimeHelpers::stringToTimePoint ( input.stints [assignedS].startTime ) ;
102- auto s2_end = TimeHelpers::stringToTimePoint ( input.stints [assignedS].endTime ) ;
100+ for (int assignedS : driverAssignments[candidate.nameId ]) {
101+ auto s1_start = input.stints [stintIndex].startTime ;
102+ auto s1_end = input.stints [stintIndex].endTime ;
103+ auto s2_start = input.stints [assignedS].startTime ;
104+ auto s2_end = input.stints [assignedS].endTime ;
103105
104106 double gap = 0.0 ;
105- if (s1_end <= s2_start) gap = std::chrono::duration< double > (s2_start - s1_end). count ( );
106- else if (s2_end <= s1_start) gap = std::chrono::duration< double > (s1_start - s2_end). count ( );
107+ if (s1_end <= s2_start) gap = std::difftime (s2_start, s1_end);
108+ else if (s2_end <= s1_start) gap = std::difftime (s1_start, s2_end);
107109 else gap = -1.0 ;
108110
109111 if (gap < minRestSec - 1.0 ) {
@@ -120,11 +122,11 @@ std::string explain_assignment_failure(
120122 if (input.maximumBusyHours > 0 ) {
121123 double busyDuration = getDuration (stintIndex);
122124 for (int k = stintIndex - 1 ; k >= 0 ; --k) {
123- if (driverAssignments[candidate.name ].count (k)) busyDuration += getDuration (k);
125+ if (driverAssignments[candidate.nameId ].count (k)) busyDuration += getDuration (k);
124126 else break ;
125127 }
126128 for (size_t k = stintIndex + 1 ; k < input.stints .size (); ++k) {
127- if (driverAssignments[candidate.name ].count ((int )k)) busyDuration += getDuration (k);
129+ if (driverAssignments[candidate.nameId ].count ((int )k)) busyDuration += getDuration (k);
128130 else break ;
129131 }
130132 if (busyDuration > input.maximumBusyHours ) {
@@ -171,8 +173,8 @@ std::string formatStintList(const std::vector<int>& indices, const jres::interna
171173std::vector<std::string> formatHumanDiagnostic (
172174 const std::map<int , jres::internal::SlackInfo>& slackInfo,
173175 const std::set<int >& unavailableVars,
174- const std::map<std::pair<std::string , int >, int >& driverWorkVars,
175- const std::map<std::pair<std::string , int >, int >& spotterWorkVars,
176+ const std::map<std::pair<jres::internal::ID , int >, int >& driverWorkVars,
177+ const std::map<std::pair<jres::internal::ID , int >, int >& spotterWorkVars,
176178 const std::vector<double >& colValues,
177179 const jres::internal::SolverInput& input,
178180 const std::vector<jres::internal::TeamMember>& driverPool,
@@ -206,14 +208,14 @@ std::vector<std::string> formatHumanDiagnostic(
206208 std::map<ViolationKey, std::vector<int >> groupedViolations;
207209 std::vector<std::string> globalViolations;
208210
209- // Build reverse map for variable index -> (Member , Stint, Role)
211+ // Build reverse map for variable index -> (MemberName , Stint, Role)
210212 std::map<int , std::tuple<std::string, int , std::string>> varToInfo;
211213
212214 for (const auto & [key, varIdx] : driverWorkVars) {
213- varToInfo[varIdx] = std::make_tuple (key.first , key.second , " Driver" );
215+ varToInfo[varIdx] = std::make_tuple (input. strings . get_string ( key.first ) , key.second , " Driver" );
214216 }
215217 for (const auto & [key, varIdx] : spotterWorkVars) {
216- varToInfo[varIdx] = std::make_tuple (key.first , key.second , " Spotter" );
218+ varToInfo[varIdx] = std::make_tuple (input. strings . get_string ( key.first ) , key.second , " Spotter" );
217219 }
218220
219221 // Check Unavailable (Priority 0)
@@ -235,23 +237,25 @@ std::vector<std::string> formatHumanDiagnostic(
235237 if (info.type .find (" Busy" ) != std::string::npos) priority = 1 ;
236238 else if (info.type .find (" Rest" ) != std::string::npos) priority = 2 ;
237239 else if (info.type .find (" Fair Share" ) != std::string::npos) priority = 2 ;
240+
241+ std::string infoMemberName = input.strings .get_string (info.memberNameId );
238242
239243 if (info.stintIndex >= 0 ) {
240244 std::string reason;
241- if (priority == 1 ) reason = " Max Busy Time exceeded (" + info. memberName + " )" ;
245+ if (priority == 1 ) reason = " Max Busy Time exceeded (" + infoMemberName + " )" ;
242246 else if (priority == 2 ) {
243- if (info.type .find (" Fair Share" ) != std::string::npos) reason = " Fair Share Rules violated (" + info. memberName + " )" ;
244- else reason = " Rest Rules violated (" + info. memberName + " )" ;
247+ if (info.type .find (" Fair Share" ) != std::string::npos) reason = " Fair Share Rules violated (" + infoMemberName + " )" ;
248+ else reason = " Rest Rules violated (" + infoMemberName + " )" ;
245249 }
246- else reason = info.type + " (" + info. memberName + " )" ;
250+ else reason = info.type + " (" + infoMemberName + " )" ;
247251
248- groupedViolations[{priority, reason, info. memberName }].push_back (info.stintIndex );
252+ groupedViolations[{priority, reason, infoMemberName }].push_back (info.stintIndex );
249253 } else {
250254 // Try to attribute global violation to stints
251255 bool assignedAny = false ;
252256 for (const auto & [vIdx, tupleInfo] : varToInfo) {
253257 auto [memName, stintIdx, role] = tupleInfo;
254- if (memName == info. memberName && colValues[vIdx] > 0.5 ) {
258+ if (memName == infoMemberName && colValues[vIdx] > 0.5 ) {
255259 std::string reason;
256260 if (priority == 1 ) reason = " Max Busy Time exceeded (" + memName + " )" ;
257261 else if (priority == 2 ) {
@@ -273,7 +277,7 @@ std::vector<std::string> formatHumanDiagnostic(
273277 else
274278 reason = " Rest Rules violated" ;
275279 }
276- globalViolations.push_back (reason + " (" + info. memberName + " )" );
280+ globalViolations.push_back (reason + " (" + infoMemberName + " )" );
277281 }
278282 }
279283 }
@@ -314,4 +318,4 @@ std::vector<std::string> formatHumanDiagnostic(
314318 return report;
315319}
316320
317- } // namespace jres::analysis
321+ } // namespace jres::analysis
0 commit comments