作業車間調度與遺傳算法Python/Java實現及應用:BitMES,基於Electron的作業車間調度系統

作業車間調度問題描述

       作業車間調度(Job shop scheduling problem, JSP) 是車間調度中最常見的調度類型,是最難的組合優化問題之一,應用領域極其廣泛,涉及航母調度,機場飛機調度,港口碼頭貨船調度,汽車加工流水線等,因此對其研究具有重大的現實意義。科學有效的生產調度不但可以提高生產加工過程中工人、設備資源的高效利用,還可縮短生產週期,降低生產成本。

作業車間調度問題描述:

一個加工系統有M臺機器,要求加工N個作業,其中,作業i包含工序數爲L_{i}。令,則L爲任務集的總工序數。其中,各工序的加工時間已確定,並且每個作業必須按照工序的先後順序加工。調度的任務是安排所有作業的加工調度排序,約束條件被滿足的同時,使性能指標得到優化。作業車間調度需要考慮如下約束:

  1. 每道工序在指定的機器上加工,且必須在前一道工序加工完成後才能開始加工。
  2. 某一時刻1臺機器只能加工1個作業。
  3. 每個作業只能在1臺機器上加工1次。
  4. 各作業的工序順序和加工時間已知,不隨加工排序的改變而改變。

問題的數學模型:

      令(i,j)表示作業i的第j個工序。S_{ij}T_{ij}分別表示(i,j)的加工起始時刻和加工時間。Z_{ijk}表示(i,j)是否在第k臺機器上加工:如果(i,j)在第k臺機器上加工,Z_{ijk} = 1;否則,Z_{ijk} = 0C_{k}爲第k臺機器的完工時間,則問題的數學模型如下:

     公式(1)爲目標函數,即優化目標,系統中使用總加工時間最短爲優化目標。公式(2)表示1個作業只能在加工完成前一道工序後纔可以加工後一道工序。公式(3)表示1個作業的第1道工序的起始加工時刻大於或等於0。公式(4)表示在1臺機牀上不會同時加工1個以上的作業。

遺傳算法

       隨着遺傳算法(genetic algorithm (GA))在組合優化問題的廣泛應用,許多人開始對遺傳算法進行深度研究。已有研究結果表明,遺傳算法對求解作業車間調度問題具有較好的效果,因此係統採用遺傳算法來解該問題,遺傳算法是計算數學中用於解決最優化的搜索算法,是進化算法的一種。進化算法最初是借鑑了進化生物學中的一些現象而發展起來的,這些現象包括遺傳、突變、自然選擇以及雜交等。系統通過模擬生物進化,包括遺傳、突變、選擇等,來不斷地產生新個體,並在算法終止時求得最優個體,即最優解。

遺傳算法解決作業車間調度問題基本步驟

  1. 初始化一定數量的種羣(染色體編碼)
  2. 計算個體適應度(染色體解碼)
  3. 採用錦標賽法選擇染色體並交叉產生新個體
  4. 個體(染色體)變異
  5. 達到遺傳代數終止算法並從中選取適應度最優的個體作爲作業車間調度問題的解

流程圖如下

遺傳算法所需參數

  1. 種羣規模:種羣中個體的數量,用populationNumber表示
  2. 染色體長度:個體的染色體的長度,用chromosomeSize表示
  3. 交叉概率:控制交叉算子的使用頻率,用crossProbability表示,並且值爲0.95
  4. 變異概率:控制變異算子的使用頻率,用mutationProbability表示,並且值爲0.05
  5. 遺傳代數:種羣的遺傳代數,用於控制遺傳算法的終止,用times來表示

遺傳算法實現基本步驟及僞代碼

1. 編碼及初始化種羣

       採用工序實數編碼來表示染色體,即M臺機器,N個工件,每個工件的工序數爲process_{i} (0 <= i < N),則染色體長度爲chromosomeSize = \sum process_{i},對染色體編碼如下:chromosome = { ..., w_i, w_j, w_k, ... }。其中w_i代表第i個工件編號,而出現的次數代表該工件的第幾道工序。例如{0, 1, 2, 1, 2, 0, 0, 1, 2},中0,1,2表示工件的編號,第幾次出現就代表第幾道工序。然後將每一次隨機生成的染色體個體加入到種羣集合中。

算法僞代碼:

2. 解碼及計算適應度

       將優化目標定義爲總加工時間最短,因此適應度定義爲最短加工時間的倒數,設fitness爲對應個體的適應度,fulfillTime爲最短加工時間,因此                                                       

其中fulfillTime的計算方法如下:

首先定義如下變量

然後從左到右遍歷個體的染色體序列{..., w_i, w_j, w_k, ...},其中w_i表示第i個工件的編號,則w_i對應的當前工序爲processIds_{w_i},設爲p。當前工件當前工序所使用的機器編號爲machine_{w_i, p},設爲m。當前工件當前工序對應的加工時間爲time_{w_i, p},設爲t。則工件的第p道工序的最晚開始時間爲          

而第m臺機器的加工時間爲                                   

工件w_i的第p道工序的結束時間爲

最後加工完所有工件的最短加工時間fulfillTime爲

從而計算出適應度fitness。

僞代碼如下:

3. 個體選擇算子

個體的選擇使用錦標賽法,其基本策略爲從整個種羣中隨機抽取n個個體讓它們競爭,選取其中最優的個體。該算子的選擇過程如下

僞代碼如下:

4. 染色體交叉算子

使用Order Crossover(OX)交叉算子,該算子的交叉步驟如下:

對於一對染色體g1, g2,首先隨機產生一個起始位置start和終止位置end,並由從g1的染色體序列從start到end的序列中產生一個子代原型

 

 將g2中不包含在child prototype的其餘編碼加入到child prototype兩側

上述步驟將產生一個child,交換g1, g2即可產生另一個child

僞代碼如下:

5. 染色體變異算子

變異的作用主要是使算法能跳出局部最優解,因此不同的變異方式對算法能否求得全局最優解有很大的影響。使用位置變異法作爲變異算子,即從染色體中隨機產生兩個位置並交換這兩個位置的值

僞代碼如下:

6. 算法整體僞代碼如下:

遺傳算法代碼實現

根據上面的步驟及僞代碼,很容易就能寫出Python及Java對應的代碼實現了,如下:

Python代碼:

from random import (randint)
from typing import (List, Tuple, Set, Dict, Any)
from utils.utils import reshape_data
from collections import namedtuple

MATRIX_SIZE = 500


# 個體對象,染色體和適應度
class Gene(object):
    def __init__(self, fitness: float = 0, chromosome = None):
        self.fitness = fitness
        self.chromosome: list = chromosome

    def __eq__(self, other):
        if isinstance(other, Gene):
            return other.fitness == self.fitness and other.chromosome == self.chromosome
        return False

    def __hash__(self):
        return hash("".join(map(lambda x: str(x), self.chromosome)))

    def __str__(self):
        return "{} => {}".format(self.chromosome, self.fitness)


# 存儲解碼結果
class GeneEvaluation:
    def __init__(self):
        self.fulfill_time = 0
        self.machine_work_time = [0 for _ in range(MATRIX_SIZE)]
        self.process_ids = [0 for _ in range(MATRIX_SIZE)]
        self.end_time = [[0 for _ in range(MATRIX_SIZE)] for _ in range(MATRIX_SIZE)]
        self.start_time = [[0 for _ in range(MATRIX_SIZE)] for _ in range(MATRIX_SIZE)]


# 遺傳算法實現
class GA:
    def __init__(self, population_number = 50, times = 10, cross_probability = 0.95,
                 mutation_probability = 0.05, workpiece_number = 0, machine_number = 0):
        self.population_number = population_number  # 種羣數量
        self.times = times  # 遺傳代數
        self.cross_probability = cross_probability  # 交叉概率
        self.mutation_probability = mutation_probability  # 突變概率

        self.workpiece_number = workpiece_number  # 工件數量
        self.machine_number = machine_number  # 機器數量
        self.process_number: int = 0  # 工序數量
        self.chromosome_size: int = 0  # 染色體長度

        self.machine_matrix = [[-1 for _ in range(MATRIX_SIZE)] for _ in range(MATRIX_SIZE)]
        self.time_matrix = [[-1 for _ in range(MATRIX_SIZE)] for _ in range(MATRIX_SIZE)]
        self.process_matrix = [[-1 for _ in range(MATRIX_SIZE)] for _ in range(MATRIX_SIZE)]

        self.genes: Set[Gene] = set()

    # 評估染色體
    def evaluate_gene(self, g: Gene) -> GeneEvaluation:
        evaluation = GeneEvaluation()
        # print(g.chromosome)
        for workpiece_id in g.chromosome:
            process_id = evaluation.process_ids[workpiece_id]
            machine_id = self.machine_matrix[workpiece_id][process_id]
            time = self.time_matrix[workpiece_id][process_id]
            evaluation.process_ids[workpiece_id] += 1
            evaluation.start_time[workpiece_id][process_id] = evaluation.machine_work_time[machine_id] \
                if process_id == 0 else max(evaluation.end_time[workpiece_id][process_id - 1],
                                            evaluation.machine_work_time[machine_id])
            evaluation.machine_work_time[machine_id] = evaluation.start_time[workpiece_id][process_id] + time
            evaluation.end_time[workpiece_id][process_id] = evaluation.machine_work_time[machine_id]
            evaluation.fulfill_time = max(evaluation.fulfill_time, evaluation.machine_work_time[machine_id])
        return evaluation

    # 計算適應度
    def calculate_fitness(self, g: Gene) -> float:
        return 1 / self.evaluate_gene(g).fulfill_time

    # 個體交叉
    def gene_cross(self, g1: Gene, g2: Gene) -> tuple:
        chromosome_size = self.chromosome_size

        def gene_generate(father: Gene, mother: Gene) -> Gene:
            index_list = list(range(chromosome_size))
            p1 = index_list.pop(randint(0, len(index_list) - 1))
            p2 = index_list.pop(randint(0, len(index_list) - 1))
            start = min(p1, p2)
            end = max(p1, p2)
            prototype = father.chromosome[start: end + 1]
            t = mother.chromosome[0:]
            for v1 in prototype:
                for i in range(len(t)):
                    if v1 == t[i]:
                        t.pop(i)
                        break
            child = Gene()
            child.chromosome = t[0: start] + prototype + t[start:]
            child.fitness = self.calculate_fitness(child)
            return child

        return gene_generate(g1, g2), gene_generate(g2, g1)

    # 突變
    def gene_mutation(self, g: Gene, n = 2) -> None:
        index_list = [i for i in range(self.chromosome_size)]
        for i in range(n):
            a = index_list.pop(randint(0, len(index_list) - 1))
            b = index_list.pop(randint(0, len(index_list) - 1))
            g.chromosome[a], g.chromosome[b] = g.chromosome[b], g.chromosome[a]

        g.fitness = self.calculate_fitness(g)

    # 初始化種羣 [0, 1, 2, 1, 2, 0, 0, 1] => 12
    def init_population(self):
        for _ in range(self.population_number):
            g = Gene()
            size = self.workpiece_number * self.machine_number
            # print(self.workpiece_number, self.machine_number)
            index_list = list(range(size))
            chromosome = [-1 for _ in range(size)]
            for j in range(self.workpiece_number):
                for k in range(self.machine_number):
                    index = randint(0, len(index_list) - 1)
                    val = index_list.pop(index)
                    if self.process_matrix[j][k] != -1:
                        chromosome[val] = j
            g.chromosome = list(filter(lambda x: x != -1, chromosome))
            # print("chromosome:", g.chromosome)
            g.fitness = self.calculate_fitness(g)
            self.genes.add(g)

    # 選擇個體,錦標賽法
    def select_gene(self, n: int = 3):

        if len(self.genes) <= 3:
            best_gene = Gene(0)
            for g in self.genes:
                if g.fitness > best_gene.fitness:
                    best_gene = g
            return best_gene

        index_list = list(range(len(self.genes)))
        index_set = {index_list.pop(randint(0, len(index_list) - 1)) for _ in range(n)}
        best_gene = Gene(0)
        i = 0
        for gene in self.genes:
            if i in index_set:
                if best_gene.fitness < gene.fitness:
                    best_gene = gene
            i += 1
        return best_gene

    # 遺傳算法
    def exec(self, parameter: List[List[Tuple]]) -> GeneEvaluation:
        # print(parameter)
        workpiece_size = len(parameter)
        for i in range(workpiece_size):
            self.chromosome_size += len(parameter[i])
            self.process_number = max(self.process_number, len(parameter[i]))
            for j in range(len(parameter[i])):
                self.machine_matrix[i][j] = parameter[i][j][0]
                self.time_matrix[i][j] = parameter[i][j][1]

        for i in range(workpiece_size):
            for j in range(self.process_number):
                if self.machine_matrix[i][j] != -1:
                    self.process_matrix[i][self.machine_matrix[i][j]] = j

        self.init_population()

        for _ in range(self.times):
            probability = randint(1, 100) / 100
            if probability < self.mutation_probability:
                index = randint(0, len(self.genes))
                i = 0
                for gene in self.genes:
                    if i == index:
                        self.gene_mutation(gene)
                        break
                    i += 1
            else:
                g1, g2 = self.select_gene(), self.select_gene()
                children = self.gene_cross(g1, g2)
                self.genes.update({*children})

        best_gene = Gene(0)
        for gene in self.genes:
            if best_gene.fitness < gene.fitness:
                best_gene = gene

        return self.evaluate_gene(best_gene)


ResultData = namedtuple("ResultData", ["fulfill_time", "row_data", "json_data"])


# 輸出結果
def schedule(data) -> ResultData:
    print(data)
    reshape = reshape_data(data)
    parameter = reshape.result
    print(parameter)
    n = len(reshape.workpiece)
    m = len(reshape.machine)  # number from 0
    print(m)
    ga = GA(workpiece_number = n, machine_number = m)
    result = ga.exec(parameter)
    p = ga.process_number
    machine_matrix = ga.machine_matrix
    row_data = []
    for i in range(n):
        for j in range(p):
            if machine_matrix[i][j] != -1:
                temp = {
                    "workpiece": reshape.workpiece[i],
                    "process": reshape.process[i][j],
                    "machine": reshape.machine[machine_matrix[i][j]],
                    "startTime": result.start_time[i][j],
                    "endTime": result.end_time[i][j]
                }
                # print(i, j, machine_matrix[i][j], result.start_time[i][j], result.end_time[i][j])
                row_data.append(temp)

    json_data = {}
    for i in range(n):
        for j in range(p):
            if machine_matrix[i][j] != -1:
                temp = {
                    "workpiece": reshape.workpiece[i],
                    "process": reshape.process[i][j],
                    "startTime": result.start_time[i][j],
                    "endTime": result.end_time[i][j]
                }
                m = reshape.machine[machine_matrix[i][j]]
                if m not in json_data:
                    json_data[m] = [temp]
                else:
                    json_data[m].append(temp)
    return ResultData(result.fulfill_time, row_data, json_data)


if __name__ == "__main__":
    # 測試數據
    d = [{'workpiece': '#W-89-10', 'process': '#P-1349-31', 'machine': '#M-8763-12', 'time': 10, 'order': 0},
         {'workpiece': '#W-89-10', 'process': '#P-6261-32', 'machine': '#M-2304-14', 'time': 21, 'order': 1},
         {'workpiece': '#W-89-10', 'process': '#P-6917-33', 'machine': '#M-6360-16', 'time': 12, 'order': 2},
         {'workpiece': '#W-5863-13', 'process': '#P-2772-34', 'machine': '#M-6557-17', 'time': 21, 'order': 0},
         {'workpiece': '#W-5863-13', 'process': '#P-468-35', 'machine': '#M-8763-12', 'time': 21, 'order': 1},
         {'workpiece': '#W-5829-8', 'process': '#P-3959-28', 'machine': '#M-2304-14', 'time': 5, 'order': 2},
         {'workpiece': '#W-5829-8', 'process': '#P-5852-27', 'machine': '#M-671-13', 'time': 11, 'order': 1},
         {'workpiece': '#W-5829-8', 'process': '#P-7792-26', 'machine': '#M-8763-12', 'time': 10, 'order': 0},
         {'workpiece': '#W-554-9', 'process': '#P-6810-29', 'machine': '#M-671-13', 'time': 5, 'order': 0}]
    print(schedule(d).row_data)

工具reshape_data函數實現 

from typing import (List, Dict)
from collections import namedtuple

test_data = [{"workpiece": '#W-5829-8',
              "process": '#P-3959-28',
              "machine": '#M-2304-14',
              "time": 5,
              "order": 2},
             {"workpiece": '#W-5829-8',
              "process": '#P-5852-27',
              "machine": '#M-671-13',
              "time": 11,
              "order": 1},
             {"workpiece": '#W-5829-8',
              "process": '#P-7792-26',
              "machine": '#M-8763-12',
              "time": 10,
              "order": 0},
             {"workpiece": '#W-554-9',
              "process": '#P-6810-29',
              "machine": '#M-671-13',
              "time": 5,
              "order": 0},
             {"workpiece": '#W-554-9',
              "process": '#P-8883-30',
              "machine": '#M-3836-15',
              "time": 10,
              "order": 1}]

ReshapeData = namedtuple("ReshapeData",
                         ["result", "workpiece", "machine", "process", "reverse_workpiece", "reverse_machine"])


def make_reverse_index(arr: list) -> dict:
    result = {}
    for i in range(len(arr)):
        result[arr[i]] = i
    return result


def filter_value(origin: list, except_value: int) -> list:
    return list(filter(lambda v: v != except_value, origin))


def reshape_data(data: List[Dict]) -> ReshapeData:
    def make_array(r: dict) -> ReshapeData:
        workpieces = list(set(map(lambda v: v["workpiece"], data)))
        machines = list(set(map(lambda v: v["machine"], data)))
        process = [-1 for _ in workpieces]
        reverse_workpieces = make_reverse_index(workpieces)
        reverse_machines = make_reverse_index(machines)
        ans = [-1 for _ in r.keys()]

        for key, val in r.items():
            # print(val, type(val))
            m = max(*map(lambda v: v["order"], val)) + 1 if len(val) > 1 else val[0]["order"]
            t = [-1 for _ in range(m + 1)]
            x = [-1 for _ in range(m + 1)]
            for p in val:
                t[p["order"]] = (reverse_machines[p["machine"]], p["time"])
                x[p["order"]] = p["process"]
            x = filter_value(x, -1)
            t = filter_value(t, -1)
            if ans[reverse_workpieces[key]] == -1:
                ans[reverse_workpieces[key]] = t
            else:
                ans[reverse_workpieces[key]].append(t)

            process[reverse_workpieces[key]] = x
        process = filter_value(process, -1)
        ans = filter_value(ans, -1)
        return ReshapeData(ans, workpieces, machines, process, reverse_machines, reverse_workpieces)

    result = {}
    for value in data:
        w = value["workpiece"]
        if w in result:
            result[w].append(value)
        else:
            result[w] = [value]
    # print(result)
    return make_array(result)


if __name__ == "__main__":
    print(reshape_data(test_data).result)
    print(reshape_data(test_data).machine)

 同理Java也很容易實現:

import java.util.*;

class GeneticAlgorithm {
    private final int populationNumber = 60;
    private final double crossProbability = 0.95;
    private final double mutationProbability = 0.05;
    private int jobNumber;
    private int machineNumber;
    private int processNumber;
    private int chromosomeSize;

    private int[][] machineMatrix = new int[1024][1024];
    private int[][] timeMatrix = new int[1024][1024];
    private int[][] processMatrix = new int[1024][1024];


    private Set<Gene> geneSet = new HashSet<>();
    private Random random = new Random();
    public GeneticAlgorithm(int jobNumber, int machineNumber) {
        this.jobNumber = jobNumber;
        this.machineNumber = machineNumber;
        for (int[] matrix : this.machineMatrix) Arrays.fill(matrix, -1);
        for (int[] process : this.processMatrix) Arrays.fill(process, -1);
    }

    private List<Integer> makeList(int n) {
        List<Integer> result = new ArrayList<>();
        for (int i = 0; i < n; i++) result.add(i);
        return result;
    }

    private Integer[] filterArray(Integer[] arr, int filterVal) {
        List<Integer> result = new ArrayList<>();
        for (int i = 0; i < arr.length; i++) {
            if (arr[i] != filterVal) {
                result.add(arr[i]);
            }
        }
        return result.toArray(new Integer[0]);
    }

    // 初始化種羣
    public  void initialPopulation() {
        for (int i = 0; i < populationNumber; i ++) {
            Gene g = new Gene();
            int size = jobNumber * machineNumber;
            List<Integer> indexList = makeList(size);
            Integer[] chromosome = new Integer[size];
            Arrays.fill(chromosome, -1);
            for (int j = 0; j < jobNumber; j++) {
                for (int k = 0; k < machineNumber; k ++) {
                    int index = random.nextInt(indexList.size());
                    int val = indexList.remove(index);
                    if (processMatrix[j][k] != -1) {
                        chromosome[val] = j;
                    }
                }
            }
            g.chromosome = filterArray(chromosome, -1);
            g.fitness = calculateFitness(g).fulfillTime;
            geneSet.add(g);
        }
    }

    public List<Integer> subArray(Integer[] arr, int start, int end) {
        List<Integer> list = new ArrayList<>();
        for (int i = start; i < end; i++) list.add(arr[i]);
        return list;
    }
    
    // 計算適應度
    public Result calculateFitness(Gene g) {
        Result result = new Result();
        for (int i = 0; i < g.chromosome.length; i ++) {
            int jobId = g.chromosome[i];
            int processId = result.processIds[jobId];
            int machineId = machineMatrix[jobId][processId];
            int time = timeMatrix[jobId][processId];
            result.processIds[jobId] += 1;
            result.startTime[jobId][processId] = processId ==0 ? result.machineWorkTime[machineId] :
                    Math.max(result.endTime[jobId][processId - 1], result.machineWorkTime[machineId]);
            result.machineWorkTime[machineId] = result.startTime[jobId][processId] + time;
            result.endTime[jobId][processId] = result.machineWorkTime[machineId];
            result.fulfillTime = Math.max(result.fulfillTime, result.machineWorkTime[machineId]);

        }
        return result;
    }
    // 交叉算子
    private Gene crossGene(Gene g1, Gene g2) {
        List<Integer> indexList = makeList(chromosomeSize);
        int p1 = indexList.remove(random.nextInt(indexList.size()));
        int p2 = indexList.remove(random.nextInt(indexList.size()));

        int start = Math.min(p1, p2);
        int end = Math.max(p1, p2);

        List<Integer> proto = subArray(g1.chromosome, start, end + 1);
        List<Integer> t = new ArrayList<>();
        for (Integer c : g2.chromosome) t.add(c);
        for (Integer val : proto) {
            for (int i = 0; i < t.size(); i++) {
                if (val.equals(t.get(i))) {
                    t.remove(i);
                    break;
                }
            }
        }

        Gene child = new Gene();
        proto.addAll(t.subList(start, t.size()));
        List<Integer> temp = t.subList(0, start);
        temp.addAll(proto);
        child.chromosome = temp.toArray(new Integer[0]);
        child.fitness = (double) calculateFitness(child).fulfillTime;
        return child;
    }
    // 突變算子
    public Gene mutationGene(Gene gene, int n) {
        List<Integer> indexList = makeList(chromosomeSize);
        for (int i = 0; i < n; i++) {
            int a = indexList.remove(random.nextInt(indexList.size()));
            int b = indexList.remove(random.nextInt(indexList.size()));
            int t = gene.chromosome[a];
            gene.chromosome[a] = gene.chromosome[b];
            gene.chromosome[b] = t;
        }
        gene.fitness = calculateFitness(gene).fulfillTime;
        return gene;
    }

    // 選擇個體
    public Gene selectGene(int n) {
        List<Integer> indexList = makeList(geneSet.size());
        Map<Integer, Boolean> map = new HashMap<>();
        for (int i = 0; i < n; i++) {
            map.put(indexList.remove(random.nextInt(indexList.size())), true);
        }
        Gene bestGene = new Gene(0xfffff);
        int i = 0;
        for (Gene gene : geneSet) {
            if (map.containsKey(i)) {
                if (bestGene.fitness > gene.fitness) {
                    bestGene = gene;
                }
            }
            i ++;
        }
        return bestGene;
    }

    public Result run(List<List<Integer[]>> job) {
        int jobSize = job.size();

        for (int i = 0; i < jobSize; i ++) {
            chromosomeSize += job.get(i).size();
            processNumber = Math.max(processNumber, job.get(i).size());
            for (int j = 0; j < job.get(i).size(); j ++) {
                machineMatrix[i][j] = job.get(i).get(j)[0];
                timeMatrix[i][j] = job.get(i).get(j)[1];

            }
        }

        for (int i = 0; i < jobSize; i++) {
            for (int j = 0;j < processNumber; j++){
                if (machineMatrix[i][j] != -1) {
                    processMatrix[i][machineMatrix[i][j]] = j;
                }
            }
        }
        initialPopulation();
        for (int i = 0; i < populationNumber; i++) {
            double p = (double) random.nextInt(100) / 100.0;
            if (p < mutationProbability) {
                int index = random.nextInt(geneSet.size());
                int k = 0;
                for (Gene gene : geneSet) {
                    if (k == index) {
                        mutationGene(gene);
                        break;
                    }
                    k ++;
                }
            } else {
                Gene g1 = selectGene(), g2 = selectGene();
                Gene child1 = crossGene(g1, g2), child2 = crossGene(g2, g1);
                geneSet.add(child1);
                geneSet.add(child2);
            }
        }
        Gene bestGene = new Gene(0xffffff);
        for (Gene gene : geneSet) {
            if (bestGene.fitness > gene.fitness) {
                bestGene = gene;
            }
        }
        return calculateFitness(bestGene);
    }

    public Gene selectGene() {
        return selectGene(3);
    }

    public Gene mutationGene(Gene gene) {
        return mutationGene(gene, 2);
    }

    static public void main(String[] args) {
        List<List<Integer[]>> job = Arrays.asList(
                Arrays.asList(new Integer[]{0, 3}, new Integer[]{1, 2}, new Integer[]{2, 2}),
                Arrays.asList(new Integer[]{0, 2}, new Integer[]{2, 1}, new Integer[]{1, 4}),
                Arrays.asList(new Integer[]{1, 4}, new Integer[]{2, 3})
        );

        int n = 3, m = 3;
        GeneticAlgorithm ga = new GeneticAlgorithm(n, m);
        Result result = ga.run(job);
        int processNumber = ga.processNumber;

        int[][] machineMatrix = ga.machineMatrix;
        System.out.println(result.fulfillTime);

        for (int i = 0; i < n; i++) {
            for (int j = 0 ; j < processNumber; j++) {
                if (machineMatrix[i][j] != -1) {
                    System.out.println(String.format("job: %d, process: %d, machine: %d, startTime: %d, endTime: %d",
                            i, j, machineMatrix[i][j], result.startTime[i][j], result.endTime[i][j]));
                }
            }
        }
    }
}



class Gene {
    public double fitness;
    public Integer[] chromosome;
    public Gene() {
        fitness = 0;
    }
    public Gene(double fitness) {this.fitness = fitness;}
}

class Result {
    public int fulfillTime = 0;
    public int[] machineWorkTime = new int[1024];
    public int[] processIds = new int[1024];
    public int[][] endTime = new int[1024][1024];
    public int[][] startTime = new int[1024][1024];
}

基於Electron的作業車間調度系統實現

寫了那麼多的遺傳算法解作業車間調度問題,當然還要有實際應用了,因此開發了一個作業車間調度系統,核心功能很簡單就是對工件、機器、工序進行增刪改查並使用遺傳算法計算調度結果,前端用甘特圖展示調度結果。(GitHub地址:https://github.com/sundial-dreams/BitMESClient,如果覺得項目不錯,別忘了點贊哦)

系統總體技術路線:採用前後端分離模式開發,基於C/S模式,客戶端使用JavaScript,Electron, React,Node.js等進行組件化開發,服務端使用express,nodejs,typescript,python,sanic,graphql等開發獨立的graphql服務或http服務,數據庫使用mysql來存儲基本的信息,redis來實現id生成,mongodb來存儲調度結果。

  1. Client端:使用JavaScript來開發PC端應用程序。基於Electron進行開發,在Electron基礎上使用React、Redux、Antd、Echarts等前端技術和包,以模塊化、組件化的方式構建一個獨立的UI頁面,對於頁面的切換使用了前端路由React-router。除此之外,通過封裝一個GraphQL類來做GraphQL查詢,以此和後端進行數據交互。通過這種方式能快速的構建一個可維護性好,UI美觀的PC端應用程序。

  2. GrapgQL Service端:使用Typescript開發的一個GraphQL服務,提供GraphQL查詢。基於NodeJS、Express、GraphQL等來構建一個GraphQL服務器,由於Node.js的異步非阻塞特性,使得構建的服務器併發能力更強。除此之外,使用TypeORM來做數據庫的對象關係映射,加快開發速度。通過這種方式能快速搭建起一個GraphQL服務端,使用GraphQL查詢來替代傳統的RESTful API能使提供的API服務可維護性、擴展性更強。

  3. Schedule Service端:使用Python開發,提供作業調度服務。基於Python異步Web框架Sanic,使得構建的服務器運行效率和併發能力都比較強,並且使用Python來實現作業車間調度算法(遺傳算法)一方面是比較容易,另一方面是Python支持多線程編程,因此多線程來優化算法也能實現。

  4. Data Storage端:數據存儲,使用MySQL來存儲一些基本的數據,如機器信息、工件信息、工件工藝信息、員工信息等等。使用Redis來存儲一些健值對信息以及Id生成,由於Redis的單線程異步非阻塞特性,使得生成的Id不存在重複。使用MongoDB來存儲調度結果,由於調度結果完全是JSON格式數據,與使用MySQL存儲相比,使用文檔數據庫MongoDB來存儲比較容易,而且查詢也比較方便。

項目運行:

首頁

管理

作業調度 

最後,如果覺得這篇文章有幫助,別忘了點贊哦

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章