Compare commits
	
		
			No commits in common. "master" and "mapping_problem_helper" have entirely different histories.
		
	
	
		
			master
			...
			mapping_pr
		
	
		
					 17 changed files with 21 additions and 460 deletions
				
			
		|  | @ -2,7 +2,7 @@ | ||||||
| 
 | 
 | ||||||
| ## Tooling | ## Tooling | ||||||
| 
 | 
 | ||||||
| - Python 3.6 | - Python 3.5 | ||||||
| - [MyPy](http://www.mypy-lang.org/ ) für statische Typchecks | - [MyPy](http://www.mypy-lang.org/ ) für statische Typchecks | ||||||
| - [Pandoc](https://pandoc.org/ ) für die Dokumentation | - [Pandoc](https://pandoc.org/ ) für die Dokumentation | ||||||
| - Python Module: siehe [requirements.txt](https://pip.pypa.io/en/latest/user_guide/#requirements-files ) | - Python Module: siehe [requirements.txt](https://pip.pypa.io/en/latest/user_guide/#requirements-files ) | ||||||
|  |  | ||||||
							
								
								
									
										23
									
								
								Readme.txt
									
										
									
									
									
								
							
							
						
						
									
										23
									
								
								Readme.txt
									
										
									
									
									
								
							|  | @ -1,23 +0,0 @@ | ||||||
| README |  | ||||||
| ----- |  | ||||||
| 
 |  | ||||||
| Für die Ausführung des Algorithmus wird Python 3 (empfohlene Version: 3.6.1) benötigt. |  | ||||||
| Die Packages, die zusätzlich gebraucht werden, können der requirements.txt entnommen werden. |  | ||||||
| (Installation kann hier einzeln oder über den Befehl: python -m pip install -r requirements.txt) |  | ||||||
| 
 |  | ||||||
| Zur Ausführung bitte im Terminal in den Ordner src gehen und dort das Skript main.py starten. |  | ||||||
| Parameter, die hierbei möglich sind: |  | ||||||
|     -h zeigt alle Optionen an |  | ||||||
|     -p aktiviert die Ausgabe über den Plotter als Diagramm |  | ||||||
|     -l wird benötigt falls die Eingabe eine Liste von Problemen ist (d.h. für jobshop1.txt) |  | ||||||
|     -i Index des Problems in der Liste (nur relevant bei -l) |  | ||||||
|     -t setzt die Starttemperatur des Simulated Annealings |  | ||||||
|     -s setzt die maximalen Umformungsschritte pro Generierung einer neuen Lösung |  | ||||||
|     -a setzt die Wahrscheinlichkeit, pro Umformungsschritt auch eine Lösung zu akzeptieren, obwohl |  | ||||||
|         noch nicht die maximalen Umformungsschritte erreicht sind |  | ||||||
| 
 |  | ||||||
| -t -s und -a müssen nicht alle gesetzt sein, dann wird der jeweilige Defaultwert verwendet |  | ||||||
| Defaultwerte: max_temp = 300, max_steps = 250, accept_prob = 0.01 |  | ||||||
| 
 |  | ||||||
| Beispielaufruf:  |  | ||||||
|     python .\main.py -p -l -i 2 -t 50 ..\inputdata\jobshop1.txt |  | ||||||
							
								
								
									
										36
									
								
								doc.md
									
										
									
									
									
								
							
							
						
						
									
										36
									
								
								doc.md
									
										
									
									
									
								
							|  | @ -1,36 +0,0 @@ | ||||||
| ## scheduling problem defined by: |  | ||||||
|   1. $m$ specialized machines |  | ||||||
|   2. tasks $\tau$ of the form $(e, i)$ with $t \in \mathbb{N}$ the execution time and $i \in \{1,2,\dots,m\}$ the machine the task has to run on |  | ||||||
|   3. $n$ jobs $T_k$ with $\forall T_k:$ linear order of tasks, with $k \in \{1,2,\dots,n\}$ |  | ||||||
|   4. Additionally, a multiset $\Omega$ of arbitrary but fixed size that contains wait states $\omega := (1, i)$ with $i \in \{1,2,\dots,m\}$ the blocked machine. |  | ||||||
| 
 |  | ||||||
| The goal is to find the fastest feasible schedule $\sigma_{min}$. |  | ||||||
| 
 |  | ||||||
| ## evaluative function |  | ||||||
|   - minimize the execution time of $\sigma$ |  | ||||||
|   - upper bound: largest processing time first |  | ||||||
|   - lower bound: max sum of execution times on one machine |  | ||||||
| 
 |  | ||||||
| ## solutions |  | ||||||
|   - list of tuples $(t, \tau)$ with $t \in \mathbb{N}$ the scheduled begin of $\tau$ |  | ||||||
| 
 |  | ||||||
| ## operations |  | ||||||
|   - $\operatorname{ins}(\omega, t)$: block a machine at time $t$ for $w$ time steps. |  | ||||||
|   - $\operatorname{xchg}(\tau_1,\tau_2)$: exchange the position of two tasks. |  | ||||||
|    |  | ||||||
| Both operations require that the start times are recomputed. |  | ||||||
| 
 |  | ||||||
| ## neighbourhood of solution |  | ||||||
| 
 |  | ||||||
|   - $\operatorname{neighbours}(\sigma) = \{x \in \Sigma | \delta(\sigma, x) \leq n\}$ with $\Sigma$ the set of all feasible schedules. |  | ||||||
|   - $\delta$: $\delta ( \sigma )=0$, $\delta ( \operatorname{op}(x)) = \delta (x) + 1$ (ass. ins has the same penalty xchg has), $x$ either op($y$) or $\sigma$  |  | ||||||
| 
 |  | ||||||
| ## constraints |  | ||||||
|   - only schedule new $\tau$ if another $\tau$ is finished |  | ||||||
|   - only schedule $\tau \in T_k$ that has no unscheduled predecessor in $T_k$ |  | ||||||
|   - only one task on a machine any given time |  | ||||||
| 
 |  | ||||||
| ## implementation in Python |  | ||||||
|   - translate problem into list of jobs, jobs into lists of tasks, ie problem = [$T_0, T_1,\dots,T_{k-1}$], $T_i$ = [$\tau_1,\tau_2,\dots$] |  | ||||||
|   - address tasks based on their indices, ie [0][1] is the second task of the first job. |  | ||||||
|   - compute only one possible next solution, rate, drop/accept. $\delta$ is computed iteratively during generation |  | ||||||
|  | @ -1,4 +0,0 @@ | ||||||
| 3 3 |  | ||||||
| 0  4 1  6 2 1 |  | ||||||
| 1  3 0 13 2 4 |  | ||||||
| 1  2 2  5 0 3 |  | ||||||
							
								
								
									
										2
									
								
								notes.md
									
										
									
									
									
								
							
							
						
						
									
										2
									
								
								notes.md
									
										
									
									
									
								
							|  | @ -26,7 +26,7 @@ | ||||||
|     - $S = \left\{(o_j,t) | o_j \in O \cup \left\{w_n | n \in \mathbb{N} \wedge w_n \text{ v.d.F. } (1, m) \right\} \wedge o_j \text{ v.d.F. } (d, m, j) \wedge t \in T \forall o \in O : \exists (o,t) \in S\right\}$ |     - $S = \left\{(o_j,t) | o_j \in O \cup \left\{w_n | n \in \mathbb{N} \wedge w_n \text{ v.d.F. } (1, m) \right\} \wedge o_j \text{ v.d.F. } (d, m, j) \wedge t \in T \forall o \in O : \exists (o,t) \in S\right\}$ | ||||||
|     - indirekt lässt sich durch laufende Operation und Zeitpunkt auch Belegung einer Maschine zu einem Zeitpunkt ermitteln |     - indirekt lässt sich durch laufende Operation und Zeitpunkt auch Belegung einer Maschine zu einem Zeitpunkt ermitteln | ||||||
|     - Optimierung: sparse speichern |     - Optimierung: sparse speichern | ||||||
| 1. Liste von (T, $o_j$) mit $T \in \mathbb{N}$ (Time), $o_j \in O$ (Tasks), j bezeichnet den Job | 1. Liste von (T, $o_j$) mit $T \in \mathbb{N}$ (Time), $o_j \in O$ (Tasks) | ||||||
|     - Operationen: |     - Operationen: | ||||||
|         - Vertauschen von 2 Jobs auf einer Maschine, selbstinvers |         - Vertauschen von 2 Jobs auf einer Maschine, selbstinvers | ||||||
|         - Verzögern von Operationen (keine expliziten Wartezustände nötig) |         - Verzögern von Operationen (keine expliziten Wartezustände nötig) | ||||||
|  |  | ||||||
|  | @ -1,5 +1,2 @@ | ||||||
| mypy | mypy | ||||||
| arpeggio | Arpeggio | ||||||
| matplotlib |  | ||||||
| numpy |  | ||||||
| tkinter |  | ||||||
|  |  | ||||||
|  | @ -1,3 +0,0 @@ | ||||||
| with import <nixpkgs> {}; |  | ||||||
| 
 |  | ||||||
|   (python3.withPackages (ps: [ps.numpy (ps.matplotlib.override {enableQt=true;}) ps.mypy ps.arpeggio])).env |  | ||||||
|  | @ -1,198 +0,0 @@ | ||||||
| from Parser import JobShopProblem as Problem |  | ||||||
| import random |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def pull_fwd(solution): |  | ||||||
|     """  |  | ||||||
|     Pull a task from a pseudo-random position to the position of  |  | ||||||
|     a random task forward. If the task directly in front is part  |  | ||||||
|     of the same job, pull that instead. The first task can never  |  | ||||||
|     be pulled forward. Will not rectify solutions. |  | ||||||
| 
 |  | ||||||
|     Returns the modified solution and the tasks index. |  | ||||||
|     """ |  | ||||||
|     old_idx = random.randint(1, len(solution)-1) |  | ||||||
|     #print("old_idx" + str(old_idx)) |  | ||||||
|     while(solution[old_idx][1][0] == solution[old_idx-1][1][0]): |  | ||||||
|         old_idx -= 1 |  | ||||||
|     #Catch case of the op to be pulled being 0 |  | ||||||
|     #print("old_idx: " + str(old_idx)) |  | ||||||
|     if(old_idx == 0): |  | ||||||
|         return pull_fwd(solution) |  | ||||||
|     new_idx = random.randint(0, old_idx-1) |  | ||||||
|     for task in solution[new_idx:old_idx]: |  | ||||||
|         if(task[1][0] == solution[old_idx][1][0]): |  | ||||||
|             #break |  | ||||||
|             return pull_fwd(solution) |  | ||||||
|     #else: |  | ||||||
|     task = solution[old_idx] |  | ||||||
|     solution.remove(task) |  | ||||||
|     solution.insert(new_idx, task) |  | ||||||
|     return rectify(solution, new_idx) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def accept(solution): |  | ||||||
|     """  |  | ||||||
|     Accept the current generated solution and evaluate it. |  | ||||||
|     Maybe skip this during the first step to generate a more |  | ||||||
|     random solution. |  | ||||||
|     """ |  | ||||||
|     return tighten(solution) |  | ||||||
|     #return solution |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def tighten(solution): |  | ||||||
|     """ |  | ||||||
|     Try to remove any holes in the schedule. |  | ||||||
|     """ |  | ||||||
| 
 |  | ||||||
|     global problem |  | ||||||
| 
 |  | ||||||
|     bound = len(solution) |  | ||||||
|     for i in range(0,bound): |  | ||||||
|         jobs = ( task for task in solution[i-1:bound:-1] if task[1][0] == solution[i][1][0] ) |  | ||||||
|         machs = ( task for task in solution[i-1:bound:-1] if problem[task[1]][1] == problem[solution[i][1]][1] ) |  | ||||||
|         job = next(jobs,None) |  | ||||||
|         mach = next(machs,None) |  | ||||||
|         times = [] |  | ||||||
|         if job: |  | ||||||
|             times += [job[0] + problem[job[1]][0]] |  | ||||||
|         if mach: |  | ||||||
|             times += [mach[0] + problem[job[1]][0]] |  | ||||||
|         if times: |  | ||||||
|             solution[i] = (max(times), solution[i][1]) |  | ||||||
|     solution.sort() |  | ||||||
|     return solution |  | ||||||
| 
 |  | ||||||
| def rectify(solution, idx): |  | ||||||
|     """  |  | ||||||
|     Transform solution by adapting the begin times and delaying |  | ||||||
|     tasks on the same machine if affected. |  | ||||||
|     """ |  | ||||||
|     solution[idx] = (solution[idx+1][0],) + solution[idx][1:] |  | ||||||
| 
 |  | ||||||
|     update_begin(solution, idx) |  | ||||||
|     correct_indices(solution, idx) |  | ||||||
|     for i in range(idx, len(solution)-1): |  | ||||||
|         #print("i: " + str(i)) |  | ||||||
|         correct_machine(solution, i) |  | ||||||
|         #print(solution) |  | ||||||
|         correct_precedence(solution, i) |  | ||||||
|         #print(solution) |  | ||||||
|     return solution |  | ||||||
| 
 |  | ||||||
| def update_begin(solution, idx): |  | ||||||
|     """ |  | ||||||
|     Update the start time of the given task wrt machine and job. |  | ||||||
|     """ |  | ||||||
| 
 |  | ||||||
|     global problem |  | ||||||
|     task = solution[idx] |  | ||||||
| 
 |  | ||||||
|     if(idx == 0): |  | ||||||
|         solution[idx] = (0,) + solution[idx][1:] |  | ||||||
|         return |  | ||||||
| 
 |  | ||||||
|     #find the next task with condition=true, if exists |  | ||||||
|     machine = ( x for x in solution[idx-1::-1] if problem[x[1]][1] == problem[task[1]][1] ) |  | ||||||
|     prev_mach = next(machine, None) #returns the task or None |  | ||||||
| 
 |  | ||||||
|     job = ( x for x in solution[idx-1::-1] if task[1][0] == x[1][0] )  |  | ||||||
|     prev_job = next(job, None) |  | ||||||
|     end_mach = 0 |  | ||||||
|     end_job = 0 |  | ||||||
|     if prev_mach: |  | ||||||
|         end_mach = problem[prev_mach[1]][0] + prev_mach[0] |  | ||||||
|     if prev_job: |  | ||||||
|         end_job = problem[prev_job[1]][0] + prev_job[0]    |  | ||||||
|     solution[idx] = (max(end_mach, end_job, task[0]),) + solution[idx][1:] |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def correct_indices(solution, idx): |  | ||||||
|     """ |  | ||||||
|     Adapt solution to reestablish ascending order of execution times. |  | ||||||
|     """ |  | ||||||
|     task = solution[idx] |  | ||||||
|     tasks = [ x for x in solution[idx:] if x[0] < task[0]] |  | ||||||
|     if tasks: |  | ||||||
|         solution.remove(task) |  | ||||||
|         solution.insert(idx + len(tasks), task) |  | ||||||
|     #[1,3,2] -> idx = 1, len([2])=1 |  | ||||||
|      |  | ||||||
| def correct_machine(solution, idx): |  | ||||||
|     """ |  | ||||||
|     Check conflicts on machines and correct if needed. |  | ||||||
|     """ |  | ||||||
|     task = solution[idx] |  | ||||||
|     end = problem[task[1]][0] + task[0] |  | ||||||
|     possible_conf = ( x for x in solution[idx+1:] if problem[x[1]][1] == problem[task[1]][1]) |  | ||||||
|     conflict = next(( x for x in possible_conf if x[0] < end ), None) |  | ||||||
|     if(conflict): |  | ||||||
|         idx = solution.index(conflict) |  | ||||||
|         solution[idx] = (end,) + solution[idx][1:] |  | ||||||
|         correct_indices(solution,idx) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def correct_precedence(solution, idx): |  | ||||||
|     """ |  | ||||||
|     Check precedence relation and correct if needed. |  | ||||||
|     """ |  | ||||||
|     task = solution[idx] |  | ||||||
|     end = problem[task[1]][0] + task[0] |  | ||||||
|     possible_conf = ( x for x in solution[idx+1:] if x[1][0] == task[1][0] ) |  | ||||||
|     conflict = next(( x for x in possible_conf if x[0] < end or x[1][1] < task[1][1]), None) |  | ||||||
|     if(conflict): |  | ||||||
|         idx = solution.index(conflict) |  | ||||||
|         #print("idx->" + str(idx)) |  | ||||||
|         if(conflict[0] < end): |  | ||||||
|             solution[idx] = (end,) + solution[idx][1:] |  | ||||||
|             correct_indices(solution,idx) |  | ||||||
|         if(conflict[1][1] < task[1][1]): |  | ||||||
|             new_start = solution[idx][0] + solution[idx][1][1] |  | ||||||
|             #print("new_start: " + str(new_start)) |  | ||||||
|             solution.remove(task) |  | ||||||
|             task = (new_start,) + task[1:] |  | ||||||
|             solution.insert(idx, task) |  | ||||||
| 
 |  | ||||||
| def generate(old_solution, steps, p=0.01): |  | ||||||
|     """ |  | ||||||
|     Generate a new solution from an existing solution with a  |  | ||||||
|     specified number of max steps. |  | ||||||
|     """ |  | ||||||
|     import sys |  | ||||||
|     print("Max steps: " + str(steps)) |  | ||||||
|     print("Accept probability: " + str(p)) |  | ||||||
|     sys.stdout.write("Start generation... ") |  | ||||||
|     solution = old_solution[:] |  | ||||||
|     option = pull_fwd #do at least one pull |  | ||||||
|     for i in range(0, steps): |  | ||||||
|         solution = option(solution) |  | ||||||
|         if(option == accept): |  | ||||||
|             break |  | ||||||
|         option = pull_fwd if p < random.random() else accept |  | ||||||
|         if ((i * 100) % steps == 0): |  | ||||||
|             sys.stdout.write(str(i*100/steps) + "%... ") |  | ||||||
|             sys.stdout.flush() |  | ||||||
|     sys.stdout.write("Done\n") |  | ||||||
|     if option != accept: |  | ||||||
|         accept(solution) |  | ||||||
|     return solution |  | ||||||
| 
 |  | ||||||
| def mock(): |  | ||||||
|     """  |  | ||||||
|     Reads a mock problem and creates the corresponding enumerated  |  | ||||||
|     solution. Should clean up the namespace afterwards. |  | ||||||
|     """ |  | ||||||
|     global problem |  | ||||||
|     from Parser.js2_style import parse_file as mockload |  | ||||||
|     from SchedulingAlgorithms.enumerate import enumerate as mockenum |  | ||||||
|     problem = mockload('../inputdata/sample') |  | ||||||
|     solution = mockenum(problem) |  | ||||||
|     del mockload |  | ||||||
|     del mockenum |  | ||||||
|     return solution |  | ||||||
| 
 |  | ||||||
| def  init(in_problem): |  | ||||||
|     global problem |  | ||||||
|     problem = in_problem |  | ||||||
|  | @ -1,32 +0,0 @@ | ||||||
| from matplotlib import pyplot as plt |  | ||||||
| from matplotlib import colors |  | ||||||
| from matplotlib import patches |  | ||||||
| import numpy as np |  | ||||||
| from SchedulingAlgorithms.simanneal import rate |  | ||||||
| import random |  | ||||||
| 
 |  | ||||||
| def create_plot(problem, solution): |  | ||||||
|      |  | ||||||
|     end = rate(solution) |  | ||||||
| 
 |  | ||||||
|     with plt.xkcd(): |  | ||||||
|         fig,ax = plt.subplots() |  | ||||||
|         col = colors.XKCD_COLORS |  | ||||||
|         del col['xkcd:white'] |  | ||||||
|         colorlist = list(col.values()) |  | ||||||
|         random.shuffle(colorlist) |  | ||||||
|         for m in range(0, problem.machines): |  | ||||||
|             mach_ops = [ x for x in solution if problem.problem_data[x[1][0]][x[1][1]][1] == m ] |  | ||||||
|             xranges = [ (x[0], problem.problem_data[x[1][0]][x[1][1]][0]) for x in mach_ops ] |  | ||||||
|             ax.broken_barh(xranges, ((problem.machines - m)*10, 9),  |  | ||||||
|                     facecolors=[colorlist[x[1][0]] for x in mach_ops]) |  | ||||||
|         ax.set_ylim(5, 5 + (problem.machines+1)*10) |  | ||||||
|         ax.set_xlim(0, 1.25 * end) |  | ||||||
|         ax.set_yticks([15 + m * 10 for m in range(0, problem.machines)]) |  | ||||||
|         ax.set_yticklabels([ problem.machines - 1 - m for m in range(0, problem.machines)] ) |  | ||||||
|         handlecolors = colorlist[0:problem.jobs] |  | ||||||
|         handles = [ patches.Patch(color = handlecolors[j], label = "Job "+str(j)) for j in range(0,problem.jobs) ] |  | ||||||
|         labels = ["Job "+str(j) for j in range(0,problem.jobs)] |  | ||||||
|         ax.legend(handles, labels) |  | ||||||
| 
 |  | ||||||
|     plt.show() |  | ||||||
|  | @ -6,33 +6,33 @@ from collections.abc import Mapping | ||||||
| __all__ = ["js1_style", "js2_style"] | __all__ = ["js1_style", "js2_style"] | ||||||
| 
 | 
 | ||||||
| grammar = """ | grammar = """ | ||||||
|         // starting point for jobshop1 input file |         # starting point for jobshop1 input file | ||||||
|         job_shop1       = skip_preface |         job_shop1       = skip_preface | ||||||
|         // eat away lines of preface, until first problem_instance is |         # eat away lines of preface, until first problem_instance is | ||||||
|         // encountered; then the list of instances start |         # encountered; then the list of instances start | ||||||
|         skip_preface    = (!problem_instance r"[^\n]+" skip_preface) / (eol skip_preface) / instance_list |         skip_preface    = (!problem_instance r"[^\n]+" skip_preface) / (eol skip_preface) / instance_list | ||||||
|         instance_list   = problem_instance (sep_line trim_ws eol problem_instance eol?)* eof_sep |         instance_list   = problem_instance (sep_line trim_ws eol problem_instance eol?)* eof_sep | ||||||
|         problem_instance = trim_ws "instance" ' ' instance_name trim_ws eol trim_ws eol sep_line description eol problem_data |         problem_instance = trim_ws "instance" ' ' instance_name trim_ws eol trim_ws eol sep_line description eol problem_data | ||||||
|         description     = r"[^\n]*" |         description     = r"[^\n]*" | ||||||
|         instance_name   = r"\w+" |         instance_name   = r"\w+" | ||||||
|         sep_line        = trim_ws plus_line trim_ws eol |         sep_line        = trim_ws plus_line trim_ws eol | ||||||
|         // lines out of multiple + signs |         # lines out of multiple + signs | ||||||
|         plus_line       = r"\+\+\++" |         plus_line       = r"\+\+\++" | ||||||
|         // EOF is a builtin rule matching end of file |         # EOF is a builtin rule matching end of file | ||||||
|         eof_sep         = trim_ws plus_line " EOF " plus_line trim_ws eol* EOF |         eof_sep         = trim_ws plus_line " EOF " plus_line trim_ws eol* EOF | ||||||
|         // entry point for jobshop2 input files |         # entry point for jobshop2 input files | ||||||
|         job_shop2       = problem_data EOF |         job_shop2       = problem_data EOF | ||||||
|         problem_data    = trim_ws num_jobs ' ' num_machines eol job_data+ |         problem_data    = trim_ws num_jobs ' ' num_machines eol job_data+ | ||||||
|         // used for skipping arbitrary number of non-breaking whitespace |         # used for skipping arbitrary number of non-breaking whitespace | ||||||
|         trim_ws         = r'[ \t]*' |         trim_ws         = r'[ \t]*' | ||||||
|         // git may change line-endings on windows, so we have to match on both |         # git may change line-endings on windows, so we have to match on both | ||||||
|         eol             = "\n" / "\r\n" |         eol             = "\n" / "\r\n" | ||||||
|         nonneg_num      = r'\d+' |         nonneg_num      = r'\d+' | ||||||
|         num_jobs        = nonneg_num |         num_jobs        = nonneg_num | ||||||
|         num_machines    = nonneg_num |         num_machines    = nonneg_num | ||||||
|         machine         = nonneg_num |         machine         = nonneg_num | ||||||
|         duration        = nonneg_num |         duration        = nonneg_num | ||||||
|         // task data for 1 job |         # task data for 1 job | ||||||
|         job_data        = ' '* machine ' '+ duration (' '+ machine ' '+ duration)* trim_ws eol |         job_data        = ' '* machine ' '+ duration (' '+ machine ' '+ duration)* trim_ws eol | ||||||
|         """ |         """ | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -1,10 +0,0 @@ | ||||||
| from Parser import JobShopProblem as Problem |  | ||||||
| 
 |  | ||||||
| def enumerate(problem): |  | ||||||
|     schedule = ( (job, task) for job in range(0, problem.jobs) for task in range(0, len(problem.get_tasks_by_job(job))) ) |  | ||||||
|     begin = 0 |  | ||||||
|     solution = [] |  | ||||||
|     for task in schedule: |  | ||||||
|         solution.append((begin, task)) |  | ||||||
|         begin += problem[task][0] |  | ||||||
|     return solution |  | ||||||
|  | @ -1,36 +0,0 @@ | ||||||
| from Generator.generator import generate |  | ||||||
| from Generator.generator import init as gen_init |  | ||||||
| from SchedulingAlgorithms.enumerate import enumerate as enum |  | ||||||
| from math import e |  | ||||||
| from random import random |  | ||||||
| 
 |  | ||||||
| def anneal(max_temp = 300, max_steps = 250, accept_prob=0.01): |  | ||||||
|     global problem |  | ||||||
|     gen_init(problem) |  | ||||||
|     temp = max_temp |  | ||||||
|     initial = enum(problem) |  | ||||||
|     current = generate(initial, problem.machines * problem.jobs * 10, 0) #Complete the iteration once fully. |  | ||||||
|     del initial |  | ||||||
|     for step in range(0, max_steps): |  | ||||||
|         new = generate(current, problem.machines * problem.jobs, accept_prob) |  | ||||||
|         new_end = rate(new) |  | ||||||
|         curr_end = rate(current) |  | ||||||
|         p = 1 / ( 1 + (e ** ((curr_end - new_end)/temp))) |  | ||||||
|         if (new_end < curr_end) or (p < random()): |  | ||||||
|             current = new |  | ||||||
|             print("Old: " + str(curr_end) + " New: " + str(new_end)) |  | ||||||
|         temp = ((max_temp-1)/(max_steps**2))*(step-max_steps)**2+1 |  | ||||||
|         print("Iteration: "+ str(step) + " Temperature: " + str(temp)) |  | ||||||
|     return current |  | ||||||
| 
 |  | ||||||
| def rate(solution): |  | ||||||
|     global problem |  | ||||||
|     last_tasks = [] |  | ||||||
|     for i in range(0,problem.jobs): |  | ||||||
|         last_tasks += [next(( x for x in solution[::-1] if x[1][0] == i), [])] |  | ||||||
|     end_times = [ problem[x[1]][0] + x[0] for x in last_tasks] |  | ||||||
|     return max(end_times) |  | ||||||
| 
 |  | ||||||
| def init(in_problem): |  | ||||||
|     global problem |  | ||||||
|     problem = in_problem |  | ||||||
|  | @ -1,10 +1,7 @@ | ||||||
| import Parser.js1_style as p | INSTANCES = [(5, 5)] | ||||||
| #import Parser.js2_style as p | TASKS = [[(1, 21), (0, 53), (4, 95), (3, 55), (2, 35)], | ||||||
| from SchedulingAlgorithms import simanneal as sim |          [(0, 21), (3, 52), (4, 16), (2, 26), (1, 71)], | ||||||
| from Output import output as o |          [(3, 39), (4, 98), (1, 42), (2, 31), (0, 12)], | ||||||
|  |          [(1, 77), (0, 55), (4, 79), (2, 66), (3, 77)], | ||||||
|  |          [(0, 83), (3, 34), (2, 64), (1, 19), (4, 37)]] | ||||||
| 
 | 
 | ||||||
| problem = p.parse_file("../inputdata/jobshop1.txt")[0] |  | ||||||
| #problem = p.parse_file("../inputdata/sample") |  | ||||||
| sim.init(problem) |  | ||||||
| solution = sim.anneal() |  | ||||||
| o.create_plot(problem, solution) |  | ||||||
							
								
								
									
										97
									
								
								src/main.py
									
										
									
									
									
								
							
							
						
						
									
										97
									
								
								src/main.py
									
										
									
									
									
								
							|  | @ -1,97 +1,6 @@ | ||||||
| #! /usr/bin/env python | #! /usr/bin/env python | ||||||
|  | def main() -> None: | ||||||
|  |     pass | ||||||
| 
 | 
 | ||||||
| import sys | if "__name__" == "__main__": | ||||||
| import getopt |  | ||||||
| from SchedulingAlgorithms import simanneal as sim |  | ||||||
| from Output import output as o |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def usage(): |  | ||||||
|     s=  """ |  | ||||||
| Command line options: |  | ||||||
|     -h      show this help |  | ||||||
|     -p      activate pretty output (requires tkinter) |  | ||||||
|     -l      assume that a file contains multiple problems, default is only 1 |  | ||||||
|     -i      index of the problem you want solved. has no effect without l |  | ||||||
|     -t      set parameter max_temp of simulated annealing |  | ||||||
|     -s      set parameter max_steps of simulated annealing |  | ||||||
|     -a      set parameter accept_prob of simulated annealing |  | ||||||
| 
 |  | ||||||
| Invocation: |  | ||||||
|     python [-hlp] file |  | ||||||
| """ |  | ||||||
|     return s |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def main(): |  | ||||||
|     js1 = False |  | ||||||
|     plot = False |  | ||||||
|     try: |  | ||||||
|         opts, args = getopt.getopt(sys.argv[1:], 'hpli:t:s:a:') |  | ||||||
|     except getopt.GetoptError as err: |  | ||||||
|         print(err) |  | ||||||
|         sys.exit() |  | ||||||
|     if ('-h', '') in opts: |  | ||||||
|         print(usage()) |  | ||||||
|     if ('-p', '') in opts: |  | ||||||
|         print("Plotting enabled.") |  | ||||||
|         from Output import output as o |  | ||||||
|         plot = True |  | ||||||
|     if('-l', '') in opts: |  | ||||||
|         js1 = True |  | ||||||
|     idx = [int(x[1]) for x in opts if x[0]=='-i']    |  | ||||||
|     idx = idx[0] if idx else -1 |  | ||||||
|     max_temp = [int(x[1]) for x in opts if x[0]=='-t']    |  | ||||||
|     max_temp = max_temp[0] if max_temp else -1 |  | ||||||
|     max_steps = [int(x[1]) for x in opts if x[0]=='-s']    |  | ||||||
|     max_steps = max_steps[0] if max_steps else -1 |  | ||||||
|     accept_prob = [int(x[1]) for x in opts if x[0]=='-a']    |  | ||||||
|     accept_prob = accept_prob[0] if accept_prob else -1 |  | ||||||
|     if not args: |  | ||||||
|         print("No file given.") |  | ||||||
|         sys.exit()             |  | ||||||
|     else: |  | ||||||
|         infile = args[0] |  | ||||||
|     if js1: |  | ||||||
|         from Parser import js1_style as parser |  | ||||||
|     else: |  | ||||||
|         from Parser import js2_style as parser |  | ||||||
|     print("Parsing file: " + infile) |  | ||||||
|     problem = parser.parse_file(infile) |  | ||||||
|     if js1: |  | ||||||
|         print("File contains " + str(len(problem)) + " problems.") |  | ||||||
|         if idx == -1: |  | ||||||
|             idx = int(input("Which problem do you want so solve? [0-" + str(len(problem)-1) + "] ")) |  | ||||||
|         problem = problem[idx] |  | ||||||
|     print(problem) |  | ||||||
|     sim.init(problem) |  | ||||||
|     if not max_temp == -1: |  | ||||||
|         if not max_steps == -1: |  | ||||||
|             if not accept_prob == -1: |  | ||||||
|                 solution = sim.anneal(max_temp, max_steps, accept_prob) |  | ||||||
|             else: |  | ||||||
|                 solution = sim.anneal(max_temp = max_temp, max_steps = max_steps) |  | ||||||
|         else: |  | ||||||
|             if not accept_prob == -1: |  | ||||||
|                 solution = sim.anneal(max_temp = max_temp, accept_prob = accept_prob) |  | ||||||
|             else: |  | ||||||
|                 solution = sim.anneal(max_temp = max_temp) |  | ||||||
|     else: |  | ||||||
|         if not max_steps == -1: |  | ||||||
|             if not accept_prob == -1: |  | ||||||
|                 solution = sim.anneal(max_steps = max_steps, accept_prob = accept_prob) |  | ||||||
|             else: |  | ||||||
|                 solution = sim.anneal(max_steps = max_steps) |  | ||||||
|         else: |  | ||||||
|             if not accept_prob == -1: |  | ||||||
|                 solution = sim.anneal(accept_prob = accept_prob) |  | ||||||
|             else: |  | ||||||
|                 solution = sim.anneal() |  | ||||||
|     print(solution) |  | ||||||
|     print(sim.rate(solution)) |  | ||||||
|     if plot: |  | ||||||
|         o.create_plot(problem, solution) |  | ||||||
| 
 |  | ||||||
| if __name__ == "__main__": |  | ||||||
|     main() |     main() | ||||||
| 
 |  | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue