5

Mam problem z optymalizacją. Chodzi o produkt, który zawiera 20 części (kolejność produkcji nie ma znaczenia). Mam 3 podobne maszyny, które mogą produkować wszystkie 20 części.Rozwiązywanie problemów z optymalizacją harmonogramu zadań lub optymalizacją bin w R

Mam 20 części reprezentowanych w minutach (tzn. To trwa 3min produkować pierwszą część i 75min do produkcji drugiej części itp)

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

Tak, aby wyprodukować 1 produkt trwa 730 min.

sum(ItemTime) 

Celem jest zminimalizowanie produkcji jednego produktu poprzez przydzielenie towaru do trzech maszyn.

sum(ItemTime/3) 

Więc rzeczywiście muszę być jak najbliżej 243.333 min (730/3)

Ilość możliwości jest ogromna 3^20

Chyba istnieje wiele różnych optymalnych rozwiązań. Chciałbym, żeby R dał mi je wszystkie. Nie potrzebuję tylko znać całkowity czas, który będzie potrzebował maszyny 1 2 i 3: muszę również wiedzieć, które przedmioty dać maszynie 1, maszynie 2 i manchine 3.

Alternatywnie, jeśli jest zbyt długi Chciałbym wybrać próbkę bez powtórzeń, która jest tak rozsądna, jak to możliwe ...

Czy mogę rozwiązać mój problem z językiem R?

Odpowiedz

11

wierzę, problem jest bliski wariant stwardnienia Knapsack problem (MKP), która jest a priori nie bułka z masłem ...

Jednak twój wymiar jest na tyle mały, że problem można rozwiązać jako programowanie mieszane (Integer Programming) (MIP). Rozwiązałem go poniżej, używając Rglpk; zajęło solverowi około czterech minut. Jeśli masz szczęście, że masz dostęp do CPLEX, zdecydowanie polecam użyć Rcplex zamiast tego, zapali to.

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 

Problem sformułowanie:

# 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)) 

Teraz go rozwiązać:

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

Myślę, że ten problem ma więcej (i inną) strukturę na każdy problem z plecakiem, więc byłbym zainteresowany, gdybyś mógł bardziej szczegółowo opisać podobieństwa. :) – huon

+0

Tak, @dbaupp. W tym konkretnym przypadku łatwo jest stwierdzić, że rozwiązanie {243, 243, 244} lub {242, 244, 244}, jeśli istnieje, jest optymalne. Można więc rozwiązać "problem wielu plecaków" (jak zdefiniowano tutaj: http://en.wikipedia.org/wiki/List_of_knapsack_problems) dla każdego z tych dwóch zestawów wag. Jeśli jeden z dwóch problemów ma rozwiązanie, w którym trzy maszyny są w pełni załadowane, wówczas znaleźliśmy optymalne rozwiązanie pierwotnego problemu. Ponownie, jest to "wariant" ... – flodel

+0

@dbaupp, jestem zaintrygowany twoim twierdzeniem, że chciwe podejście jest optymalne. Na początku myślałem "nie ma mowy!", Ale ponieważ nie mogę znaleźć kontrprzykładu, jestem coraz bardziej przekonany, że możesz mieć rację. Jeśli tak, to zabiłem mrówkę z młotem! – flodel

8

Edit: Oczywiście problem ten jest nieco inny do jednego pamiętam, bo jak @han wystawach, algorytm ten nie jest optymalna, jedynie przybliżeniem (choć nie ma gwarancji, że „makespan” z tego algorytmu jest nigdy nie więcej niż 4/3 * optymalny makespan w ogóle i 11/9 * optymalny dla 3 maszyn.).

Link @han pod warunkiem, że jest powiązany z the multiprocessor scheduling article, co jest dokładnie równoznaczne z tym problemem. Artykuł mówi nam, że problem jest w rzeczywistości NP-trudny. Co oznacza, że ​​nie ma algorytmu wielomianowego czasu do obliczenia optymalnej odpowiedzi (znacznie mniej niż O(n log n), jak to mamy tutaj).


można po prostu użyć algorytm zachłanny: przejść przez liście i przydzielić pracę, która trwa najdłużej do maszyny, która obecnie posiada najmniejszą pracę przydzieloną do niego.

Jako przykład rozważmy posiadanie tylko c(5,3,6,1,2) jako czasu produkcji części. Najpierw posortuj to w porządku malejącym: c(6,5,3,2,1), a następnie przejdź przez to (w kolejności), przypisując zadania.

 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 

Więc maszyna 1 sprawia, że ​​część, która trwa 6 minut, maszyna 2 sprawia, że ​​te, które zajmują 1 i 5 minut i maszyna 3 sprawia, że ​​ten, który zajmuje 3 i 2.

Widać, że w krok 4, maszyna o najkrótszym łącznym czasie to maszyna 3, dlatego przypisaliśmy do niej numer 2.

Z pamięci ten algorytm jest w rzeczywistości optymalny; chociaż nie mam linku do tego roszczenia. Nie wiem też, czy można go dostosować, aby uzyskać wszystkie możliwe optymalne wyniki.


Jeśli zdefiniować funkcję, która przyjmuje jedną pracę oraz listę maszyn z obecnej pracy, można użyć Reduce przypisać wszystkie zadania. Pojedyncza cesja praca może wyglądać mniej więcej tak:

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

(nie lubię linię machines[[which.machines]] ... Jestem pewien, że istnieje lepszy sposób, aby zmodyfikować listę w określonym indeksie.)

a potem przypisanie może być tak:

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

(nie lubię wiersz rozpoczynający machines <-: Jestem pewien, że to neater sposób tworzenia listy długości n, ale nie mogę znajdź to.)

Na przykład, to daje:

> 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 

Ostatnim krokiem jest wypracowanie których praca odpowiada której czas: może to być wykonane przez pracę wstecz Po przypisaniu razy (można to zrobić w przybliżeniu liniowy czas, ponieważ istnieje relatywnie proste odwzorowanie od czasu do zadania i na odwrót) lub poprzez modyfikację allocate i assign.job, aby śledzić indeksy zadań (jeśli zamierzasz to zrobić, wtedy funkcja order będzie bardziej użyteczna niż sort, a przy użyciu ramek danych zamiast wektorów, aby przechowywać czasy w jednej kolumnie i indeksy w innym).

(Należy zauważyć, że rozwiązanie to jest kilka razy szybciej niż inne, ponieważ druga odpowiedź jest zasilane za pomocą wyżej algorytmy, które są ewentualnie nie przesada dla tego problemu ... „być może”, bo” m jeszcze nie w 100% pewien, że ten algorytm jest optymalny.)

+2

Twoje podejście jest bliskie algorytmowi najlepszego dopasowania do zmniejszenia [problemu pakowania bin] (http://en.wikipedia.org/wiki/Bin_packing_problem), ale nie jest optymalne. Jako kontrprzykład należy rozważyć wagi 10,6,5,4,3,2. Twój algorytm przypisuje zadania w następujący sposób: (10), (6,3,2) i (5,4), z zadaniami o wartości 11. Optymalnym zadaniem jest (10), (6,4) i (5,3 , 2) z produkcją 10. – han

+0

Ah, dzięki za to! Najwyraźniej pamiętałem niepoprawnie. (Będę edytować moją odpowiedź, aby to wyjaśnić.) – huon

+0

@han, artykuł na temat pakowania koszyka powiązany z [ten] (https://en.wikipedia.org/wiki/Multiprocessor_scheduling), który jest dokładnie tym samym problemem, a wymieniony tam algorytm jest dokładnie tym, który opisałem powyżej. – huon

4

Jak zauważono w innych odpowiedzi to jest związane z bin packing problem. Prosty algorytm pakowania bin jest już zaimplementowany w pakiecie BBmisc; możemy zastosować tę istniejącą funkcję tutaj, aby uzyskać proste i szybkie rozwiązanie:

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 

W tym przypadku natychmiast produkuje optymalne rozwiązanie za pomocą 3 pojemników.Możemy potwierdzić rozmiary bin Solution:

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 

Jeśli binPack produkuje wstępną rozwiązanie przy użyciu zbyt wiele pojemników, może być umieszczany w pętli for, która zwiększa binsize i zwraca tylko rozwiązanie, gdy nie ma więcej niż 3 pojemniki na wyjściu binPack.

ciekawe, binPack zwraca rozwiązanie z tych samych rozmiarach odbiornika jako odpowiedź flodel jest wyżej, ale z różnych zadań w pojemnikach 2 i 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 

Podczas binPack zapewnia szybki i prosty sposób na rozwiązanie tego problemu, jego opis zauważa, że ​​ten algorytm jest prosty i nie może wrócić optymalne rozwiązanie:

Maps elementy numeryczne w X w grupy z sumy mniejszy lub równy pojemności. Stosowany jest bardzo prosty, zachłanny algorytm, który nie jest tak naprawdę zoptymalizowany pod kątem szybkości. Jest to funkcja wygody dla mniejszych wektorów , a nie konkurencyjnego rozwiązania dla prawdziwego problemu z koszowaniem. Jeśli element x przekracza pojemność, zostanie zgłoszony błąd.

+0

dzięki dużo sam – S12000

Powiązane problemy