Flexible Job Shop Scheduling Theory and GA Recurrence with Fuzzy Processing Time (python)

1. Fuzzy job shop

1.1 Fuzzy numbers

The fuzzy set A on the domain of discourse X is represented by the membership function u(x), and u(x) takes the value [0,1]. If A is a triangular fuzzy number, A can be expressed as (a1, aM, a2). If A is a four-corner fuzzy number, A can be expressed as (a1, a2, a4, a5). Each fuzzy number and membership function are as follows:
insert image description here
insert image description here
For the workpiece processing time and completion time under uncertain conditions, triangular fuzzy numbers are used to describe. For the delivery date under uncertain conditions, trapezoidal fuzzy numbers are used to describe it. For example, for the first operation O11 of job1, its fuzzy processing time on machine 1 is represented by triangular fuzzy numbers (4, 7, 12), and the three numbers represent the best, most likely, and worst processing time respectively. A data case of flexible job shop scheduling problem with 4job and 2machine with fuzzy processing time is as follows: the parentheses are the actual processing time, which can be ignored
insert image description here

1.2 Triangular fuzzy number operation

【1】Sakawa, M., & Mori, T. (1999). An efficient genetic algorithm for job-shop scheduling problems with fuzzy processing time and fuzzy duedate. Computers & Industrial Engineering, 36(2), 325-341. doi:https://doi.org/10.1016/S0360-8352(99)00135-7
【2】Sakawa, M., & Kubota, R. (2000). Fuzzy programming for multiobjective job shop scheduling with fuzzy processing time and fuzzy duedate through genetic algorithms. European Journal of Operational Research, 120(2), 393-407. doi:https://doi.org/10.1016/S0377-2217(99)00094-6

To solve the workshop scheduling problem, you will encounter some calculations of processing time, such as calculating the processing start time and processing completion time. Like definite number operations, fuzzy number operations are also very important, mainly including fuzzy number summation and large operations and a comparison of fuzzy numbers.

  • Summation: calculates the fuzzy completion time of each operation [1]

insert image description here

  • Take the big: Calculate the fuzzy start time of each operation [1]

insert image description here

  • Comparison: The fuzzy completion time is the sum of the fuzzy processing time, so it becomes a triangular fuzzy number. If you want to minimize the maximum fuzzy completion time, you need to compare some fuzzy completion time values ​​[2]
    insert image description here
  • example

Suppose there are 2✖️2 JSP questions:
Job 1: Machine 1 (2, 5, 6), Machine 2 (5, 7, 8)
Job 2: Machine 2 (3, 4, 7), Machine 1 (1, 2 , 3)
Then the fuzzy start time of the second operation of Job1 is (2, 5, 6)V(3, 4, 7), that is (3, 5, 7); the fuzzy completion time is (3, 5, 7) +(5, 7, 8)=(8, 12, 15)
Suppose there are 4 triangular fuzzy numbers A1=(2,5,8), A2=(3,4,9), A3=(3,5 ,7),A4=(4,5,8), A4,A1,A3,A2 can be obtained according to the comparison principle

1.3 Fuzzy Gantt chart

Since the start time and completion time of each operation are triangular fuzzy numbers, its Gantt chart is also different from the normal Gantt chart, as shown in the figure below, the fuzzy start time of each operation is below the line, and the fuzzy completion time is above the line. Each triangle is the image of the aforementioned membership function. If it is the first processing on the machine, it is represented by a rectangle. For example, the fuzzy start time of O41 is (4,5,7), and the next step is to process on M1, and the fastest fuzzy end time of M1 is (6,10,14) of O31, so the fuzzy start time of O42 is (6, 10,14).
insert image description here
insert image description here

2. FJSP+fuzzy processing time+GA

2.1 GA algorithm settings

复现文章:【3】Lei, D. M. (2010). A genetic algorithm for flexible job shop scheduling with fuzzy processing time. International Journal of Production Research, 48(10), 2995-3013. doi:10.1080/00207540902814348

Different from the previous introduction, [3] proposed a new max operation operator, which is determined directly according to the rank result, and the larger value of the two triangular fuzzy numbers s, t is either s or t
insert image description here

  • encoding and decoding (two-string)

It is represented by two layers of coding, one layer is the operation sequence, and the other layer is the selection machine. Note that the machine allocation code of the second layer corresponds to the machine that each operation is arranged in order, and has nothing to do with the first layer of coding. For example, operation 011 is the final processing, and the processing machine is 1.
insert image description here
In the two-level encoding in some other literatures, the second-level machine encoding corresponds to the processing machine for each operation under the first-level encoding, which is different from here. The following is another encoding method, such as operation 023 final processing, and the processing machine is M5.
insert image description here
The fitness value is the objective function value (fuzzy completion time)

  • select (tournament select)

Use the elite strategy, that is, retain the best individuals in each generation of the population. A roulette wheel approach is not suitable due to ambiguous target values, so a tournament select is used. With replacement, two individuals are randomly selected from the population, and the individual with a smaller fitness value is selected to enter the new population

  • Cross (TPX; GPX/GPPX)

Divide the population into two subpopulations, A and B, representing job sequences and machine assignments, respectively. For the machine allocation part, the cross uses two point crossover (two point crossover TPX). For the job sequence part, two kinds of crossovers are used: generalized position crossover (GPX) and generalization of the precedence preservative crossover (GPPX)
GPX: Select substring S from parent1, such as S=1231, find each element in S in parent2 Note that the elements are in order. For example, 1 in S is the second occurrence in parent1, so find the second occurrence of 1 in parent2. After deleting S, parent2 becomes 32414234. Insert S into parent2, the position is equal to the position of S in parent1, that is, pos=4
insert image description here
GPPX: Set a string with a value of [1,2], and the sub-table represents successive selection of genes from parent1(2), if from parent1 A gene is selected in , and its corresponding gene in parent2 is deleted
insert image description here

  • Mutation (swap)

For an individual, two genes are randomly selected and exchanged

  • algorithm

Randomly generate the initial population P of N individuals;
perform tournament select on P;
divide P into two subpopulations A and B, representing the job sequence and machine allocation part respectively;
perform GPPX or GPX crossover and swap mutation
on population A ; Execute TPX crossover and swap mutation;
merge A and B to generate a new population and calculate fitness value;
iterate until the end

2.2 python code

The operation sequence uses the GPPX crossover operator, the crossover rate=0.8, the mutation rate=0.1, the number of populations=100, the number of iterations=1000, the second coding method, the following is the GA part, the complete code https://github.com/bujibujibiuwang /solve-fuzzy-FJSP-with-GA

import random
from params import get_args
from Shop import Shop
from utils import *


class GA(object):
    def __init__(self, args, shop):
        self.shop = shop
        self.cross_rate = args.cross_rate
        self.mutate_rate = args.mutate_rate
        self.pop_size = args.pop_size
        self.elite_number = args.elite_number

        self.chrom_size = self.shop.job_nb * self.shop.op_nb
        self.pop = []

    def encode(self):
        init_pop = []
        for _ in range(self.pop_size):
            one_string = []
            for _ in range(self.shop.op_nb):
                one_string += list(np.random.permutation(self.shop.job_nb))
            random.shuffle(one_string)
            two_string = [random.randint(0, self.shop.machine_nb-1) for _ in range(self.chrom_size)]
            individual = np.vstack([one_string, two_string])
            init_pop.append(individual)
        return np.array(init_pop)

    def decode(self, pop1):
        fuzzy_fitness = []
        certain_fitness = []
        for individual in pop1:
            fuzzy_completion_time = self.shop.process_decode1(individual)
            fuzzy_fitness.append(fuzzy_completion_time)
            certain_fitness.append(value(fuzzy_completion_time))
        return fuzzy_fitness, certain_fitness

    def selection(self, pop2, fuzzy_fitness, certain_fitness):
        """
        tournament selection + elite_strategy
        """
        pop2 = pop2.tolist()
        sorted_pop = sorted(pop2, key=lambda x: certain_fitness[pop2.index(x)], reverse=False)
        new_pop = sorted_pop[:self.elite_number]
        while len(new_pop) < self.pop_size:
            index1, index2 = random.sample(list(range(10, self.pop_size)), 2)
            if rank(fuzzy_fitness[index1], fuzzy_fitness[index2]) == fuzzy_fitness[index1]:
                new_pop.append(pop[index2])
            else:
                new_pop.append(pop[index1])
        return np.array(new_pop)

    def crossover_machine(self, pop_machine):
        """
        two point crossover (TPX)
        """
        temp = pop_machine.copy().tolist()
        new_pop = []
        while len(temp) != 0:
            parent1, parent2 = random.sample(temp, 2)
            temp.remove(parent1)
            temp.remove(parent2)
            if random.random() < self.cross_rate:
                pos1, pos2 = sorted(random.sample(list(range(self.chrom_size)), 2))
                offspring1 = parent1[:pos1] + parent2[pos1:pos2] + parent1[pos2:]
                offspring2 = parent2[:pos1] + parent1[pos1:pos2] + parent2[pos2:]
            else:
                offspring1 = parent1
                offspring2 = parent2
            new_pop.append(offspring1)
            new_pop.append(offspring2)
        return np.array(new_pop)

    def crossover_job(self, pop_job):
        """
        generalisation of the precedence preservative crossover (PPX)
        """
        temp = pop_job.copy().tolist()
        new_pop = []
        for parent1 in temp:
            if random.random() < self.cross_rate:
                new_individual = []
                parent2 = pop_job[random.randint(0, self.pop_size-1)].tolist()
                string = random.choices([0, 1], k=self.chrom_size)
                for choose in string:
                    if int(choose) == 0:
                        new_individual.append(parent1[0])
                        parent2.remove(parent1[0])
                        parent1 = parent1[1:]
                    else:
                        new_individual.append(parent2[0])
                        parent1.remove(parent2[0])
                        parent2 = parent2[1:]
                new_pop.append(new_individual)
            else:
                new_pop.append(parent1)
        return np.array(new_pop)

    def mutation(self, part):
        """
        swap
        """
        for individual in part:
            if random.random() < self.mutate_rate:
                pos1, pos2 = random.sample(list(range(self.chrom_size)), 2)
                individual[pos1], individual[pos2] = individual[pos2], individual[pos1]
        return part

    @staticmethod
    def elite_strategy(pop3, fitness):
        best_fitness = [np.inf, np.inf, np.inf]
        best_individual = None
        for k, individual in enumerate(pop3):
            if rank(fitness[k], best_fitness) == best_fitness:
                best_fitness = fitness[k]
                best_individual = individual
        return best_individual, best_fitness

2.3 Test results

Use the instance1 test in the literature [3], the instance1 in the literature finds the optimal solution [20, 31, 40], and I test the optimal solution [20, 31, 41]

0:old best:[inf, inf, inf], now best:[47, 70, 89], now mean:99.9475
100:old best:[28, 41, 54], now best:[34, 42, 52], now mean:48.41
200:old best:[25, 38, 46], now best:[25, 38, 47], now mean:38.92
300:old best:[25, 36, 45], now best:[25, 36, 45], now mean:38.2425
400:old best:[21, 33, 44], now best:[21, 33, 44], now mean:35.2775
500:old best:[21, 31, 41], now best:[24, 31, 40], now mean:34.475
600:old best:[21, 31, 41], now best:[21, 31, 42], now mean:34.35
700:old best:[19, 31, 42], now best:[19, 31, 42], now mean:33.5275
800:old best:[20, 31, 41], now best:[19, 31, 42], now mean:32.6575
900:old best:[20, 31, 41], now best:[20, 31, 41], now mean:34.175

The fuzzy Gantt chart is as follows and
insert image description here
the iteration curve is as follows
insert image description here

Guess you like

Origin blog.csdn.net/weixin_45526117/article/details/128650540