Compare commits

..

No commits in common. "master" and "output" have entirely different histories.

14 changed files with 24 additions and 181 deletions

View file

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

View file

@ -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
View file

@ -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

View file

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

View file

@ -1,5 +1,3 @@
mypy mypy
arpeggio Arpeggio
matplotlib matplotlib
numpy
tkinter

View file

@ -1,3 +0,0 @@
with import <nixpkgs> {};
(python3.withPackages (ps: [ps.numpy (ps.matplotlib.override {enableQt=true;}) ps.mypy ps.arpeggio])).env

View file

@ -38,8 +38,8 @@ def accept(solution):
Maybe skip this during the first step to generate a more Maybe skip this during the first step to generate a more
random solution. random solution.
""" """
return tighten(solution) #return tighten(solution)
#return solution return solution
def tighten(solution): def tighten(solution):

View file

View file

@ -1,4 +1,4 @@
from matplotlib import pyplot as plt import matplotlib.pyplot as plt
from matplotlib import colors from matplotlib import colors
from matplotlib import patches from matplotlib import patches
import numpy as np import numpy as np
@ -11,9 +11,7 @@ def create_plot(problem, solution):
with plt.xkcd(): with plt.xkcd():
fig,ax = plt.subplots() fig,ax = plt.subplots()
col = colors.XKCD_COLORS colorlist = list(colors.XKCD_COLORS.values())
del col['xkcd:white']
colorlist = list(col.values())
random.shuffle(colorlist) random.shuffle(colorlist)
for m in range(0, problem.machines): 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 ] mach_ops = [ x for x in solution if problem.problem_data[x[1][0]][x[1][1]][1] == m ]
@ -29,4 +27,4 @@ def create_plot(problem, solution):
labels = ["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) ax.legend(handles, labels)
plt.show() plt.show()

View file

@ -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
""" """

View file

@ -1,10 +1,10 @@
import Parser.js1_style as p #import Parser.js1_style as p
#import Parser.js2_style as p import Parser.js2_style as p
from SchedulingAlgorithms import simanneal as sim from SchedulingAlgorithms import simanneal as sim
from Output import output as o from Output import output as o
problem = p.parse_file("../inputdata/jobshop1.txt")[0] #problem = p.parse_file("../inputdata/jobshop1.txt")[0]
#problem = p.parse_file("../inputdata/sample") problem = p.parse_file("../inputdata/sample")
sim.init(problem) sim.init(problem)
solution = sim.anneal() solution = sim.anneal()
o.create_plot(problem, solution) o.create_plot(problem, solution)

View file

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