5
5
import ast
6
6
import json
7
7
import re
8
+ import math
8
9
import numpy as np
9
10
from datetime import datetime , timedelta
10
11
@@ -48,11 +49,13 @@ def filter_slots_by_constraints(time_slots, constraints, day):
48
49
for slot in time_slots :
49
50
start_time , end_time = slot
50
51
if constraints ['no_meetings_before' ]:
51
- no_meetings_before = datetime .strptime (f"{ constraints ['no_meetings_before' ]} :00" , "%H:%M" )
52
+ nb = int (constraints ['no_meetings_before' ])
53
+ no_meetings_before = datetime .strptime (f"{ nb } :00" , "%H:%M" )
52
54
if start_time < no_meetings_before :
53
55
continue
54
56
if constraints ['no_meetings_after' ]:
55
- no_meetings_after = datetime .strptime (f"{ constraints ['no_meetings_after' ]} :00" , "%H:%M" )
57
+ na = int (constraints ['no_meetings_after' ])
58
+ no_meetings_after = datetime .strptime (f"{ na } :00" , "%H:%M" )
56
59
if end_time >= no_meetings_after :
57
60
continue
58
61
if constraints ['no_meetings_on_weekends' ] and day in ['Saturday' , 'Sunday' ]:
@@ -86,6 +89,8 @@ def run_programmatic_tests(self, instance):
86
89
solution = solution .strip ('"' ).strip ('`' ).strip ('\n ' )
87
90
if check_time_slot_format (solution ):
88
91
result ['format_programmatic' ] = 1
92
+ else :
93
+ result ['format_programmatic' ] = 0
89
94
result .update (self .check_availability_programmatic (instance , solution ))
90
95
result .update (self .check_meeting_duration_programmatic (instance , solution ))
91
96
result .update (self .check_buffer_time_programmatic (instance , solution ))
@@ -102,6 +107,7 @@ def run_programmatic_tests(self, instance):
102
107
passed_constraints .append (value )
103
108
result ['all_correct' ] = all_correct
104
109
result ['fraction_passed' ] = np .mean (passed_constraints )
110
+ result .update (self .compute_constrainedness_programmatic (instance ))
105
111
return result
106
112
107
113
def is_formatted (self , solution ):
@@ -224,12 +230,14 @@ def check_time_restrictions_programmatic(self, instance, solution):
224
230
no_meetings_after = instance ['constraints' ].get ('no_meetings_after' )
225
231
226
232
if no_meetings_before :
227
- no_meetings_before = datetime .strptime (f"{ no_meetings_before } :00" , "%H:%M" )
233
+ nb = int (no_meetings_before )
234
+ no_meetings_before = datetime .strptime (f"{ nb } :00" , "%H:%M" )
228
235
if start_time < no_meetings_before :
229
236
return {'time_restrictions_programmatic_check' : 0 }
230
237
231
238
if no_meetings_after :
232
- no_meetings_after = datetime .strptime (f"{ no_meetings_after } :00" , '%H:%M' )
239
+ na = int (no_meetings_after )
240
+ no_meetings_after = datetime .strptime (f"{ na } :00" , '%H:%M' )
233
241
if end_time > no_meetings_after :
234
242
return {'time_restrictions_programmatic_check' : 0 }
235
243
return {'time_restrictions_programmatic_check' : 1 }
@@ -290,4 +298,61 @@ def check_specific_times_programmatic(self, instance, solution):
290
298
result = 0
291
299
else :
292
300
result = 1
293
- return {'specific_times_programmatic_check' : result }
301
+ return {'specific_times_programmatic_check' : result }
302
+
303
+ def compute_constrainedness_programmatic (self , instance ):
304
+ """
305
+ Compute the constrainedness of the problem based on the constraints and availability.
306
+ The constrainedness is defined as (1 - the ratio of feasible slots to total slots).
307
+ The higher the constrainedness, the more constrained the problem is.
308
+ """
309
+ params = instance ['params' ]
310
+ constraints = instance ['constraints' ]
311
+ metadata = instance ['metadata' ]
312
+ if not instance ['constraints' ]['buffer_time_before_and_after_meeting' ]:
313
+ buffer_time_before_and_after_meeting = 0
314
+ else :
315
+ buffer_time_before_and_after_meeting = instance ['constraints' ]['buffer_time_before_and_after_meeting' ]
316
+ total_slots = 0
317
+ feasible_slots = 0
318
+ for day in params ['days_of_week' ]:
319
+ common_time_slots = None
320
+ union_time_slots = None
321
+ availability = json .loads (metadata ['availability' ].replace ("'" , '"' ))
322
+ for participant , schedule in availability .items ():
323
+ if day in schedule :
324
+ participant_time_slots = []
325
+ participant_time_slots_unconstrained = []
326
+ for time_slot in schedule [day ]:
327
+ start_time , end_time = parse_time_block (time_slot )
328
+ time_slots = generate_time_slots (start_time , end_time , params ['granularity' ])
329
+ time_slots = filter_slots_by_duration (time_slots , constraints ['meeting_duration' ])
330
+ participant_time_slots_unconstrained .extend (time_slots )
331
+ time_slots = generate_time_slots (start_time , end_time , params ['granularity' ])
332
+ time_slots = filter_slots_by_duration (time_slots , constraints ['meeting_duration' ] + buffer_time_before_and_after_meeting * 2 )
333
+ time_slots = filter_slots_by_constraints (time_slots , constraints , day = day )
334
+ participant_time_slots .extend (time_slots )
335
+ if common_time_slots is None :
336
+ common_time_slots = set (participant_time_slots )
337
+ else :
338
+ common_time_slots = common_time_slots .intersection (participant_time_slots )
339
+ if union_time_slots is None :
340
+ union_time_slots = set (participant_time_slots_unconstrained )
341
+ else :
342
+ union_time_slots = union_time_slots .union (participant_time_slots_unconstrained )
343
+ if common_time_slots :
344
+ feasible_slots += len (common_time_slots )
345
+ if union_time_slots :
346
+ total_slots += len (union_time_slots )
347
+
348
+ # Calculate constrainedness ratio
349
+ if total_slots > 0 :
350
+ constrainedness_ratio = 1 - (feasible_slots / total_slots )
351
+ else :
352
+ constrainedness_ratio = 1
353
+
354
+ # Bucket the constrainedness ratio into intervals of 0.2
355
+ constrainedness_bucket = round (math .floor (constrainedness_ratio / 0.1 ) * 0.1 , 4 )
356
+
357
+ # Add test result
358
+ return {'constrainedness' : constrainedness_ratio , 'constrainedness_bucket' : constrainedness_bucket }
0 commit comments