Job shop scheduling problem description

Job Shop Scheduling problem (JSP) is the most common type of Job shop scheduling and one of the most difficult combinatorial optimization problems. It is widely used in aircraft carrier scheduling, airport aircraft scheduling, port terminal cargo ship scheduling, automobile processing assembly line, etc. Therefore, it is of great practical significance to study it. Scientific and effective production scheduling can not only improve the efficient utilization of workers and equipment resources in the production process, but also shorten the production cycle and reduce the production cost.

A machining system hasMA machine, processing requirementsNHomework, among them, homeworkiIncluding the number of procedures is. To make,LIs the total working order of the task set. Among them, the processing time of each process has been determined, and each operation must be processed in accordance with the sequence of the process. The task of scheduling is to arrange the processing scheduling of all jobs, so that the performance index can be optimized when the constraints are satisfied. Job shop scheduling needs to consider the following constraints:

  1. Each process is processed on a designated machine and can only be processed after the completion of the previous process.
  2. One machine can only process one job at a time.
  3. Each job can only be processed once on 1 machine.
  4. The process sequence and processing time of each operation are known and do not change with the change of processing sequence.

Mathematical model of the problem:

Let (I,j) represent the JTH operation of operation I.andRespectively represent the initial processing time and processing time of (I,j).Denotes whether (I,j) is processed on machine K: If (I,j) is processed on machine K,; Otherwise,.Is the completion time of the k machine, then the mathematical model of the problem is as follows:

Formula (1) is the objective function, that is, the optimization objective. The shortest total processing time is used as the optimization objective in the system. Formula (2) means that an operation can only process the latter one after the former one is finished. Formula (3) means that the initial machining time of the first step of an operation is greater than or equal to 0. Formula (4) means that no more than one job will be processed simultaneously on one machine tool.

Genetic algorithm (ga)

With the wide application of genetic algorithm (GA) in combinatorial optimization problems, many people begin to conduct in-depth research on GA. Existing research results show that genetic algorithm has a good effect on solving job-shop scheduling problem, so the system uses genetic algorithm to solve the problem, genetic algorithm is used to solve the optimization of the search algorithm in computational mathematics, is a kind of evolutionary algorithm. Evolutionary algorithms were originally developed based on some phenomena in evolutionary biology, including heredity, mutation, natural selection and hybridization. The system simulates biological evolution, including heredity, mutation, selection, etc., to continuously generate new individuals, and obtains the optimal individuals, namely the optimal solution, when the algorithm terminates.

The basic steps of genetic algorithm to solve job shop scheduling problem

  1. Initializing a number of populations (chromosomal code)
  2. Calculating individual fitness (chromosome decoding)
  3. The chromosomes were selected by tournament method and crossed to produce new individuals
  4. Individual (chromosome) variation
  5. The genetic algebraic termination algorithm is proposed and the fittest individual is selected as the solution of job-shop scheduling problem

The flow chart is as follows

Parameters required for genetic algorithm

  1. Population size: the number of individuals in a population, expressed by populationNumber
  2. ChromosomeSize chromosomeSize chromosomeSize
  3. Crossover probability: controls the frequency of crossover operator, which is expressed by crossProbability and the value is 0.95
  4. MutationProbability: control the frequency of mutation operator, expressed by mutationProbability, and the value is 0.05
  5. Genetic algebra: The genetic algebra of a population, used to control the termination of a genetic algorithm, expressed by times

Genetic algorithm to achieve the basic steps and pseudo-code

1. Code and initialize the population

Process real number coding is adopted to represent chromosomes, that is, M machines and N workpieces, and the number of processes of each workpiece is, the chromosome length isAnd encode the chromosomes as follows:. Among themRepresents the I th workpiece number, and the number of occurrences represents the number of processes of the workpiece. For example, {0, 1, 2, 1, 2}, where 0, 1, 2 represents the number of the workpiece, and the number of the occurrence represents the number of the process. Each randomly generated chromosome individual is then added to the population.

​​2. Decoding and calculation of fitness

And the optimization goal is defined as the shortest total processing time, so fitness is defined as the reciprocal of the shortest processing time, let fitness be the fitness of the corresponding individual, and fulfillTime be the shortest processing time, soAnd fulfillTime is calculated as follows:

First, define the following variables

It then traverses the individual’s chromosome sequence from left to right, includingIs the number of the i-th workpiece, thenThe corresponding current procedure is, set it to p. Current workpiece The machine number used in the current process is, set it to m. The processing time corresponding to the current process of the current workpiece is, set it to t. Then the latest start time of the PTH process of the workpiece is

And the processing time of machine M is

artifactsThe end time of procedure P isThe shortest processing time of fulfillTime is fulfillTime

So we can calculate the fitness.

3. Individual selection operator

The selection of individuals uses the tournament method, whose basic strategy is to randomly select N individuals from the whole population and let them compete, and select the best one among them. The selection process of this operator is as follows

4. Chromosome crossover operator

Use the Order Crossover(OX) operator, which performs the following Crossover steps:

For a pair of chromosomes G1, G2, a start position and a stop position are randomly generated, and a progeny prototype is generated from the sequence from start to end of the chromosome sequence from G1

Add the rest of the g2 encoding that is not included in Child Prototype to both sides of Child Prototype

The above steps produce one child, and swapping G1, G2 produces another child

5. Chromosome variation operator

The main function of mutation is to make the algorithm jump out of the local optimal solution, so different mutation modes have a great influence on whether the algorithm can get the global optimal solution. The position mutation method is used as the mutation operator, that is, two positions are randomly generated from chromosomes and the values of these two positions are exchanged

Genetic algorithm code implementation

Based on the above steps and pseudocode, it is easy to write Python and Java corresponding code implementation (C++ implementation is here: genetic algorithm and job shop scheduling C++ implementation), as follows:

Python code:

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


# Individual objects, chromosomes and fitness
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)


# Store the result of decoding
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)]


# Genetic algorithm implementation
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  # Population size
        self.times = times  # Genetic algebra
        self.cross_probability = cross_probability  # Crossover probability
        self.mutation_probability = mutation_probability  # Mutation probability

        self.workpiece_number = workpiece_number  # Number of workpieces
        self.machine_number = machine_number  # Number of machines
        self.process_number: int = 0  # Number of processes
        self.chromosome_size: int = 0  # Chromosome length

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

    # Evaluating chromosomes
    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

    # Calculate fitness
    def calculate_fitness(self, g: Gene) -> float:
        return 1 / self.evaluate_gene(g).fulfill_time

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

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

    # initialize population [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)
                    ifself.process_matrix[j][k] ! =- 1:
                        chromosome[val] = j
            g.chromosome = list(filter(lambdax: x ! =- 1, chromosome))
            # print("chromosome:", g.chromosome)
            g.fitness = self.calculate_fitness(g)
            self.genes.add(g)

    # Select individuals, tournament method
    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

    # Genetic algorithm
    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):
                ifself.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"])


# output result
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):
            ifmachine_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):
            ifmachine_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__":
    # Test data
    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)
Copy the code

Tool reshape_data function implementation

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(lambdav: 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)
Copy the code

Java is also easy to implement:

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]);
    }

    // Initialize the population
    public  void initialPopulation(a) {
        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;
    }
    
    // Calculate the fitness
    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;
    }
    // the crossover operator
    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;
    }
    // The mutation operator
    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;
    }

    // Select the individual
    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(a) {
        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(a) {
        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];
}Copy the code

Implementation of job shop Scheduling system based on Electron

I have written so many genetic algorithms to solve job shop scheduling problems, but of course there must be practical applications, so I developed a job shop scheduling system, the core function is very simple is to add, delete, change and check the workpiece, machine, process and use genetic algorithm to calculate the scheduling results, the front end with gantt chart display scheduling results. (GitHub address: github.com/sundial-dre… And don’t forget to give it a thumbs up if you like it.)



Overall technical route of the system: Using the front and back end separation mode development, based on C/S mode, the client side uses JavaScript, Electron, React, Node.js and other components for development, the server side uses Express, NodeJS, typescript, Python, SANic, Graphql and others developed independent GraphQL service or HTTP service. Mysql was used to store basic information in the database, REDis was used to generate ID, and mongodb was used to store scheduling results.

  1. Client: Use JavaScript to develop PC applications. Developed based on Electron, React, Redux, Antd, Echarts and other front-end technologies and packages are used on the basis of Electron to build an independent UI page in a modular and componentalized way. The react-Router front-end route is used for page switching. In addition, GraphQL queries are made by encapsulating a GraphQL class to interact with the back-end data. In this way, it can quickly build a PC application with good maintainability and beautiful UI.

  2. GrapgQL Service: A GraphQL Service developed with Typescript that provides GraphQL queries. Build a GraphQL server based on NodeJS, Express, GraphQL, etc. Due to the asynchronous non-blocking feature of Node.js, the constructed server has stronger concurrency capability. In addition, TypeORM is used to do the object relation mapping of the database to speed up the development. In this way, a GraphQL server can be quickly built. Using GraphQL query to replace traditional RESTful API can make the API service provided more maintainable and expansible.

  3. Schedule Service: Developed using Python to provide job scheduling services. Based on the Python asynchronous Web framework Sanic, makes the construction of the server running efficiency and concurrency are relatively strong, and the use of Python to achieve job shop scheduling algorithm (genetic algorithm) is relatively easy on the one hand, on the other hand, Python supports multi-threaded programming, so multi-threaded optimization algorithm can also be achieved.

  4. Data Storage side: Data Storage, using MySQL to store some basic Data, such as machine information, workpiece information, workpiece process information, employee information and so on. Redis is used to store some key pair information as well as Id generation. Due to the single-threaded asynchronous non-blocking nature of Redis, generated ids are not duplicated. MongoDB is used to store the scheduling results, because the scheduling results are completely JSON format data, compared with MySQL storage, using the document database MongoDB is easier to store, and the query is also more convenient.

Project Operation:

Home page

management

Job scheduling



Finally, don’t forget to like this post if you found it helpful