Project-Platypus / Platypus

A Free and Open Source Python Library for Multiobjective Optimization
GNU General Public License v3.0
563 stars 153 forks source link

Using multidimensional array in Platypus #143

Closed sabrinadraude closed 4 years ago

sabrinadraude commented 4 years ago

Hi there,

I am currently working on a scheduling problem using Platypus.

I have made Platypus work for one day worth of scheduling. However I am having issues using it for more than one day. For example for two days, I would need to input an array of 2 days by eight slots for eight jobs per day and sixteen jobs in total. The amount of slots in a day can vary.

I was wondering does Platypus work for multidimensional arrays, or should I work out a different way to combine all the job slots together to put into the chromosome and then split them?

Here is what I put in the optimiser:

N = 10 problem = Problem(len(c_time_added_up), 2, 2) # c_time_added_up is the list of two lists, each list contains eight slots. (I know this is currently wrong) problem.directions[1] = Problem.MINIMIZE problem.directions[0] = Problem.MAXIMIZE problem.constraints[:] = ">=0" problem.types[:] = Integer(0, my_counter_again - 1) problem.function = lambda x: evaluation_function2(x, jobs, One_hour_extra, total_allowed_time) algorithm = NSGAII(problem) algorithm.run(N)

Cheers! Any hints will be greatly appreciated :)

jetuk commented 4 years ago

I would use numpy to reshape the values returned from platypus to a 2D array as required by your function. This may require a minor modification of your function if it is assuming a list of lists instead of a 2D array.

import numpy as np

c_time_added_up = np.array(c_time_added_up)

problem = Problem(c_time_added_up.size, 2, 2)  # .size is the total number of elements in the array

problem.function = lambda x: evaluation_function2(np.reshape(x, (2, 8)), jobs, One_hour_extra, total_allowed_time)

If you do need to have it as a list of lists then np.reshape(x, (2, 8)).tolist() will reshape and then convert to lists. This will obviously only work if your inner lists are all the same length, but should extended to multiple dimensions.

sabrinadraude commented 4 years ago

Thank you for the useful feedback.

Unfortunately my lists can vary in length... I'll see if I can edit the evaluation function to try and incorporate a change in list length.

Cheers :)

jetuk commented 4 years ago

In that case you can keep a record of the length of each list, and then use a function something like this to convert the output from platypus to your list of lists format. I've not tested this, and it could probably be made much more concise.

def unflatten(x, list_lengths):
    lists = []
    i = 0
    j = 0
    for length in list_lengths:
        j += length
        lists.append(x[i:j])
        i += length
    return lists

problem.function = lambda x: evaluation_function2(unflatten(x, list_lengths), jobs, One_hour_extra, total_allowed_time)
sabrinadraude commented 4 years ago

Thanks! I got a few errors trying to implement it that way. Instead I just printed off my whole solution and then interpreted the Pareto Front from there.

prints all the results in an array with no space for different days

sol_parameters = (100, multiple_days_assigned_size) sol = np.zeros(sol_parameters, dtype=int) for i in range(100): for j in range(multiple_days_assigned_size): sol[i][j] = problem.types[0].decode(algorithm.result[i].variables[j])

all_jobs = [] for i in sol: all_jobs.append(i)

The resultant list of all the jobs on the Pareto front, in a list of days

output_list = [] for i in range(len(all_jobs)): input_list = all_jobs[i] slices = length_of_lists iterable = iter(input_list) output_list += [[list(it.islice(iterable, sl)) for sl in slices]]