def test_create_simple_bundles(self): tasks = OrderedDict() tasks[1] = Task(10, 2) tasks[3] = Task(20, 0) tasks[2] = Task(5, 0) tasks[0] = Task(5, 0) tasks[4] = Task(5, 0) bundles = TaskBundle.create_simple_bundles(tasks, 20, 3) bundle = bundles[0] self.assertEqual(bundle.load, 20) self.assertEqual(bundle.mapping, 0) self.assertEqual(len(bundle.task_ids), 1) self.assertEqual(bundle.task_ids[0], 3) bundle = bundles[1] self.assertEqual(bundle.load, 15) self.assertEqual(bundle.mapping, 0) self.assertEqual(len(bundle.task_ids), 3) self.assertEqual(bundle.task_ids[0], 2) self.assertEqual(bundle.task_ids[1], 0) self.assertEqual(bundle.task_ids[2], 4) bundle = bundles[2] self.assertEqual(bundle.load, 10) self.assertEqual(bundle.mapping, 2) self.assertEqual(len(bundle.task_ids), 1) self.assertEqual(bundle.task_ids[0], 1)
def test_check_task_loads(self): tasks = OrderedDict() tasks[1] = Task(10, 2) tasks[3] = Task(20, 0) tasks[2] = Task(5, 0) self.assertTrue(TaskBundle.check_task_loads(tasks, 30)) self.assertTrue(TaskBundle.check_task_loads(tasks, 20)) self.assertFalse(TaskBundle.check_task_loads(tasks, 19.9999)) self.assertFalse(TaskBundle.check_task_loads(tasks, 1))
def test_create_inverse_mapping(self): tasks = OrderedDict() tasks[1] = Task(10, 2) tasks[3] = Task(20, 0) tasks[2] = Task(5, 0) mapping = TaskBundle.create_inverse_mapping(tasks, 3) self.assertEqual(len(mapping[0]), 2) self.assertEqual(len(mapping[1]), 0) self.assertEqual(len(mapping[2]), 1) self.assertEqual(mapping[0][0], 3) self.assertEqual(mapping[0][1], 2) self.assertEqual(mapping[2][0], 1)
def test_check_consistency(self): self.assertTrue(self.context.check_consistency()) # invalid mapping self.context.tasks[0].mapping = 20 self.assertFalse(self.context.check_consistency()) self.context.tasks[0].mapping = 2 self.assertTrue(self.context.check_consistency()) # invalid load self.context.tasks[0].load = -10 self.assertFalse(self.context.check_consistency()) self.context.tasks[0].load = 1 self.assertTrue(self.context.check_consistency()) # too many tasks self.context.tasks[10] = Task() self.assertFalse(self.context.check_consistency()) self.context.tasks.pop(10) self.assertTrue(self.context.check_consistency()) # too many resources self.context.resources[10] = Resource self.assertFalse(self.context.check_consistency()) self.context.resources.pop(10) self.assertTrue(self.context.check_consistency()) # invalid load self.context.resources[0].load = -10 self.assertFalse(self.context.check_consistency()) self.context.resources[0].load = 8 self.assertTrue(self.context.check_consistency())
def test_add_task(self): bundle = TaskBundle() task = Task(5.0, 10) bundle.add_task(2, task) self.assertEqual(bundle.load, 5.0) self.assertEqual(len(bundle.task_ids), 1) self.assertEqual(bundle.task_ids[0], 2) self.assertFalse(bundle.is_empty())
def from_loads(task_loads, num_resources=2, rng_seed=0, name='from_loads'): """ Creates a scheduling context from a list of task loads and a number of resources. All tasks are initially mapped to resource zero. Parameters ---------- task_loads : list of int or float Loads of tasks. num_resources : int Number of resources in the context. rng_seed : int, optional Random number generator seed used previously. name : string Name of the method used for the creation of the context. Returns ------- Context object Scheduling context based on the list of loads, or empty context. """ context = Context() # empty context # Starts adding resources to the context for identifier in range(num_resources): context.resources[identifier] = Resource(0) # Starts adding tasks to the context for identifier in range(len(task_loads)): task = Task(task_loads[identifier], 0) context.tasks[identifier] = task # Adds the load of the task to the initial resource context.resources[0].load += task_loads[identifier] # Updates experiment information context.experiment_info.num_tasks = len(task_loads) context.experiment_info.num_resources = num_resources context.experiment_info.rng_seed = rng_seed context.experiment_info.algorithm = name # Checks the context for any inconsistencies # If any are found, we generate an empty context if context.check_consistency() is False: context = Context() return context
def test_update_task(self): task = Task() task.load = 10.0 task.mapping = 5 self.assertEqual(task.load, 10.0) self.assertEqual(task.mapping, 5)
def test_float_load(self): task = Task(10.0, 5) self.assertEqual(task.load, 10.0) self.assertEqual(task.mapping, 5)
def from_csv(filename='scenario.csv'): """ Imports a scheduling context from a CSV file. Parameters ---------- filename : string Name of the CSV file containing the scheduling context. Returns ------- Context object Scheduling context read from CSV file or empty context. Raises ------ IOError If the file cannot be found or open. KeyError If the file does not contain the correct keywords (e.g., 'tasks'), or tasks have inconsistent identifiers or negative loads. Notes ----- Each line of the file contains a task identifier, its load, and its mapping. A header informs the number of tasks, resources, and other information. """ context = Context() try: with open(filename, 'r') as csvfile: # Example of the format of the first line to read # "# tasks:5 resources:3 rng_seed:0 algorithm:none" first_line = csvfile.readline() # We decompose the line into a dict while ignoring extremities first_info = dict(x.split(':') for x in first_line[2:-1].split(' ')) # and we save each component for use num_tasks = int(first_info['tasks']) num_resources = int(first_info['resources']) algorithm = first_info['algorithm'] rng_seed = int(first_info['rng_seed']) experiment = ExperimentInformation(num_tasks, num_resources, algorithm, rng_seed) context.experiment_info = experiment # After that, we read the other lines of the CSV file reader = csv.DictReader(csvfile) for line in reader: # Each line generates a task context.tasks[int(line['task_id'])] = Task( load=float(line['task_load']), mapping=int(line['task_mapping']), ) # Finally, we generate the list of resources # and update them based on tasks mapped to them for identifier in range(num_resources): context.resources[identifier] = Resource(0) for task in context.tasks.values(): resource_id = task.mapping context.resources[resource_id].load += task.load except IOError: print('Error: could not read file '+filename+'.') except KeyError: print('Error: file '+filename+' contains non-standard' + ' formating or incorrect keys.') # Checks the context for any inconsistencies # If any are found, we generate an empty context if context.check_consistency() is False: context = Context() return context