5

У меня проблема оптимизации. Речь идет о продукте, который содержит 20 частей (порядок производства не имеет значения). У меня есть 3 похожие машины, которые могут производить все 20 частей.Решение задачи планирования или оптимизации упаковки бинов в R

У меня есть 20 частей, представленных в течение нескольких минут (то есть. Он принимает 3Min производить первую часть и 75 мин для получения второй части, и т.д.)

ItemTime<-c(3,75,55,12,45,55,11,8,21,16,65,28,84,3,58,46,5,84,8,48) 

Так для производства 1 продукта она занимает 730 минимум

sum(ItemTime) 

Целью является минимизация производства одного продукта путем распределения товара на три машины.

sum(ItemTime/3) 

Так на самом деле мне нужно, чтобы быть как можно ближе 243.333 мин (730/3)

Сумма возможности огромна 3^20

Я предполагаю, что есть много различных оптимальных решений. Я бы хотел, чтобы я дал им все. Мне не нужно знать только общее время, которое понадобится машинам 1 2 и 3: мне также нужно знать, какие предметы нужно отдать машине 1, машине 2 и маньчине.

В качестве альтернативы, если она слишком длинная Я хотел бы выбрать образец без повторения, который является настолько разумным, насколько это возможно ...

Могу ли я решить свою проблему с помощью языка R?

ответ

11

Я считаю, что ваша проблема близкий вариант множественного ранце задачи (MKP), которая, априори, а не кусок пирога ...

Однако ваше измерение достаточно мало, что проблема может быть решена как программирование с смешанным целым (MIP). Я решил использовать его ниже, используя Rglpk; он принял решателя около четырех минут. Если вам посчастливилось иметь доступ к CPLEX, я бы настоятельно рекомендовал вместо этого использовать Rcplex, он курит его.

ItemTime<-c(3,75,55,12,45,55,11,8,21,16,65,28,84,3,58,46,5,84,8,48) 
N <- length(ItemTime) 
M <- 3 

Постановка задачи:

# variables are in this order: 
# z: slack variable for the max of (s1, s2, s3) 
# s1: sum of times for machine 1 
# s2: sum of times for machine 2 
# s3: sum of times for machine 3 
# a1-a20: booleans for assignment to machine1 
# b1-b20: booleans for assignment to machine1 
# c1-c20: booleans for assignment to machine1 

obj <- c(1, rep(0, 3 + 3*N)) 

mat <- rbind(
    c(1, -1, 0, 0, rep(0, M*N)),      # z >= s1 
    c(1, 0, -1, 0, rep(0, M*N)),      # z >= s2 
    c(1, 0, 0, -1, rep(0, M*N)),      # z >= s3 
    c(0, -1, 0, 0, ItemTime, rep(0, N), rep(0, N)), # s1 = ... 
    c(0, 0, -1, 0, rep(0, N), ItemTime, rep(0, N)), # s2 = ... 
    c(0, 0, 0, -1, rep(0, N), rep(0, N), ItemTime), # s3 = ... 
    cbind(matrix(0, N, 4), diag(N), diag(N), diag(N)) # a_i + b_i + c_i = 1 
) 

dir <- c(">=", ">=", ">=", "==", "==", "==" , rep("==", N)) 

rhs <- c(rep(0, 2*M), rep(1, N)) 

types <- c(rep("C", 1+M), rep("B", M*N)) 

Теперь давайте решать ее:

Rglpk_solve_LP(obj, mat, dir, rhs, types, max=FALSE, verbose=TRUE) 

# GLPK Simplex Optimizer, v4.47 
# INTEGER OPTIMAL SOLUTION FOUND 
# $optimum 
# [1] 244 
# 
# $solution 
# [1] 244 243 243 244 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 1 0 0 
# [31] 1 1 1 0 1 0 0 0 1 0 1 0 1 0 1 0 0 0 1 1 0 0 0 1 0 1 0 1 0 1 
# [61] 0 0 0 1 
# 
# $status 
# [1] 0 
+0

Я думаю, что эта проблема имеет больше (и другую) структуру для любой проблемы с рюкзаком, поэтому мне было бы интересно, если бы вы могли подробнее рассказать о сходствах. :) – huon

+0

Да, @dbaupp. В этом конкретном случае легко сказать, что решение {243, 243, 244} или {242, 244, 244}, если оно существует, является оптимальным. Поэтому можно было бы решить «проблему с несколькими рюкзаками» (как определено здесь: http://en.wikipedia.org/wiki/List_of_knapsack_problems) для каждого из этих двух наборов весов. Если одна из двух проблем имеет решение, в котором три машины полностью загружены, то мы нашли оптимальное решение исходной задачи. Опять же, это «вариант» ... – flodel

+0

@dbaupp, меня заинтриговало ваше утверждение о том, что жадный подход оптимален. Сначала я думал «нет!», Но поскольку я не могу найти встречный пример, я все больше убеждаюсь, что вы правы. Если это так, я убил муравья с кувалдой! – flodel

8

Редактировать: Очевидно, эта проблема немного отличается от той, которую я помню, потому что, как показывает @han, этот алгоритм не является оптимальным, просто приближением (хотя есть гарантия того, что «makepan» из этого алгоритма не более 4/3 * оптимальный вариант в целом и 11/9 * оптимальный для 3 машин.).

Ссылка @han предоставлена ​​связанная с the multiprocessor scheduling article, что в точности эквивалентно этой проблеме. В статье говорится, что проблема на самом деле NP-hard. Это означает, что для вычисления оптимального ответа нет алгоритма полиномиального времени (тем более, что мы имеем здесь O(n log n)).


Вы можете просто использовать жадный алгоритм: перейти через список и назначить задание, которое занимает самый длинный в машине, которая в настоящее время имеет наименьшую работу, возложенную на нее.

В качестве примера рассмотрим только наличие c(5,3,6,1,2) в качестве вашей части времени производства. Сначала вы сортируете это в порядке убывания: c(6,5,3,2,1), а затем пройдите через него (в порядке), назначая задачи.

 Step: 1 2 3 4 5 
Machine 1: 6 6 6 6 6 
Machine 2: - 5 5 5 5,1 
Machine 3: - - 3 3,2 3,2 

Так машина 1 делает часть, которая занимает 6 минут, машина 2 делает те, которые занимают 1 и 5 минут и машина 3 делает тот, который принимает 3 и 2.

Вы можете видеть, что в шаг 4, машина с наименьшим общим временем - это машина 3, поэтому мы назначили ей 2.

Из памяти этот алгоритм фактически оптимален; хотя у меня нет ссылки на эту претензию. Я также не знаю, можете ли вы адаптировать его, чтобы получить все возможные оптимальные результаты.


Если определить функцию, которая принимает одно задание и список машин с их текущей работы, вы можете использовать Reduce назначить все рабочие места. Единственное назначение работы может выглядеть примерно так:

assign.job <- function(machines, job) { 
    which.machines <- which.min(lapply(machines, sum)) 
    machines[[which.machines]] <- c(machines[[which.machines]], job) 
    machines 
} 

(я не люблю machines[[which.machines]] линию ... Я уверен, что есть лучший способ изменить список по заданному индексу.)

а то задание может быть как:

allocate <- function(num.machines, job.times) { 
    machines <- lapply(1:num.machines, function(...) c()) 
    Reduce(assign.job, 
      sort(job.times, decreasing=TRUE), 
      machines) 
} 

(я не люблю строку, начинающуюся machines <-: Я уверен, что есть аккуратнее способ создания списка длина n, но я не могу найти его.)

На вашем примере, это дает:

> allocate(3,ItemTime) 
[[1]] 
[1] 84 58 46 45 8 3  # total time: 244 

[[2]] 
[1] 84 55 55 21 16 8 5 # total time: 244 

[[3]] 
[1] 75 65 48 28 12 11 3 # total time: 242 

Последний шаг является разработка которой работа соответствует тому времени: это может быть сделано, работая в обратном направлении после назначения раз (это может быть сделано примерно в линейном время, так как существует относительно простое сопоставление от времени до работы и наоборот) или путем изменения allocate и assign.job для отслеживания индексов заданий (если вы собираетесь это сделать, то функция order будет более полезной чем sort, а также использовать фреймы данных вместо векторов, чтобы хранить времена в одном столбце и индексы в другом).

(Следует отметить, что это решение несколько раз быстрее, чем другие, так как другой ответ, используя более высокий приведенные алгоритмы, которые возможно не избыточны для этой проблемы ... «возможно», потому что я м еще не 100% уверен, что этот алгоритм является оптимальным.)

+2

Ваш подход близок к алгоритму с наилучшим подходом для проблемы с упаковкой [bin] (http://en.wikipedia.org/wiki/Bin_packing_problem), но это не оптимально. В качестве встречного примера рассмотрим веса 10,6,5,4,3,2. Ваш алгоритм присваивает задания следующим образом: (10), (6,3,2) и (5,4), с разницей 11. Оптимальное назначение: (10), (6,4) и (5,3 , 2) с макарой 10. – han

+0

А, спасибо за это! Я, очевидно, помнил неправильно. (Я отредактирую свой ответ, чтобы сделать это ясно.) – huon

+0

@han, статья упаковки бина, связанная с [этой] (https://en.wikipedia.org/wiki/Multiprocessor_scheduling), что является точно такой же проблемой, и приведенный там алгоритм - это тот, который я описал выше. – huon

4

Как отмечалось в других ответах это связано с bin packing problem. В пакете BBmisc уже реализован простой алгоритм упаковки бункеров; мы можем применить эту существующую функцию здесь для простого и быстрого решения:

library(BBmisc) 

binlimit <- 3 # specify how many bins 
binsize <- ceiling(sum(ItemTime)/binlimit) # calculate the minimum possible bin size (244) 
binPack(ItemTime, binsize) # pack the bins 

[1] 3 1 2 3 3 2 2 3 3 3 2 3 1 3 2 3 3 1 3 3 

В этом случае, он мгновенно дает оптимальное решение с использованием 3 бункеров.Мы можем подтвердить бен размеры Решения по:

library(dplyr) 
df <- data.frame(ItemTime, bins) 
df %>% group_by(bins) %>% summarise (time = sum(ItemTime)) 

    bins time 
1 1 243 
2 2 244 
3 3 243 

Если binPack производит первоначальное решение, используя слишком много бункеров, он может быть помещен в для цикла, что приращение значения binsize и только возвращает решение, когда нет больше 3 бункера на выходе binPack.

Интересно, что binPack возвращает решение с теми же бин размерами, как ответ flodel в выше, но с различными заданиями в бункерах 2 и 3:

ItemTime Rglpk binPack 
1   3  3  3 
2  75  1  1 
3  55  2  2 
4  12  2  3 
5  45  3  3 
6  55  3  2 
7  11  2  2 
8   8  2  3 
9  21  2  3 
10  16  3  3 
11  65  2  2 
12  28  3  3 
13  84  1  1 
14  3  3  3 
15  58  2  2 
16  46  3  3 
17  5  2  3 
18  84  1  1 
19  8  2  3 
20  48  3  3 

Хотя binPack обеспечивает быстрый и простой способ решить эту проблему, его описание отмечает, что этот алгоритм прост и не может вернуть оптимальное решение:

Карты числовых элементы в й на группы с суммой меньше или равна мощности. Используется очень простой жадный алгоритм, который на самом деле не оптимизирован для скорости. Это удобная функция для меньших векторов , а не конкурентный решатель для реальной проблемы с бинанием. Если элемент x превышает емкость, возникает ошибка.

+0

спасибо большое sam – S12000

Смежные вопросы