Compare commits

...

28 commits

Author SHA1 Message Date
Trolli Schmittlauch f46b2cdd9f move nix environment to fit lorri tooling 2022-03-19 03:05:24 +01:00
Trolli Schmittlauch c18dde9cc4 add nix environment 2022-03-19 03:05:24 +01:00
Trolli Schmittlauch 412b572afb update grammar comments syntax to arpeggio-1.9.0 2022-03-19 03:05:21 +01:00
lukasstracke 03c5fb612d finale Version: Readme für Dr. Gaggl, Reqs ergänzt (kp ob notwendig), weiss als Farbe im Plot ausschliessen, main um simanneal-params ergaenzt 2017-07-13 00:03:27 +02:00
lukasstracke d6f3eb9dd3 Merge branch 'devel' of PSSAI_Team/JobShopScheduling into master 2017-07-12 22:34:23 +02:00
Trolli Schmittlauch 9574aca0b9 follow python package convention 2017-07-12 21:58:53 +02:00
Trolli Schmittlauch 52a2f0ca2f fix remaining merge conflict artifacts 2017-07-12 20:06:18 +02:00
Maximilian Schlosser ab58830fcb merge 2017-07-12 18:21:55 +02:00
Maximilian Schlosser 3ccbed4d3a pretty printing 2017-07-12 18:17:05 +02:00
Trolli Schmittlauch 2a214b93bd fix import typo
contributes to #20
2017-07-12 18:00:22 +02:00
maxschlosser a719dd974c Merge branch 'main' of PSSAI_Team/JobShopScheduling into devel 2017-07-12 17:55:30 +02:00
Maximilian Schlosser 460a4a8166 main method, command line options 2017-07-12 17:55:16 +02:00
maxschlosser dd18b64203 Merge branch 'output' of PSSAI_Team/JobShopScheduling into devel 2017-07-12 17:54:24 +02:00
lukasstracke 22196bdfa6 Merge branch 'simanneal' of PSSAI_Team/JobShopScheduling into devel 2017-07-12 17:51:33 +02:00
lukasstracke d88e5d9e91 Legendary Output, v1.1 2017-07-12 17:50:36 +02:00
lukasstracke be28f9b11f Output 1.0, Beispiel s. example.py 2017-07-12 16:33:53 +02:00
lukasstracke 435291679b Merge branch 'output' of ssh://git.orlives.de:1337/PSSAI_Team/JobShopScheduling into output 2017-07-12 13:51:32 +02:00
Maximilian Schlosser 304dc401f7 Added matplotlib as requirement 2017-07-11 13:18:14 +02:00
maxschlosser 0874188b06 Merge branch 'task_job_verwechslung' of PSSAI_Team/JobShopScheduling into master 2017-06-26 21:43:58 +02:00
maxschlosser 457eaf74be Update 'doc.md' 2017-06-26 21:43:14 +02:00
Trolli Schmittlauch e82512f2b0 correct possible ambiguation of and 2017-06-26 14:16:02 +02:00
Maximilian Schlosser 3b8fd60ede Merge branch 'master' of ssh://git.orlives.de:1337/PSSAI_Team/JobShopScheduling 2017-06-23 19:05:56 +02:00
Maximilian Schlosser 58c386175e merge 2017-06-23 19:05:31 +02:00
maxschlosser b68ff321bb Merge branch 'treffen1' of PSSAI_Team/JobShopScheduling into master 2017-06-23 19:02:27 +02:00
Maximilian Schlosser 21f78a0479 initial documentation 2017-06-23 19:00:50 +02:00
Maximilian Schlosser f9f852ced1 Merge branch 'treffen1' into documentation 2017-06-23 09:56:20 +02:00
Trolli Schmittlauch 26c229929d require python 3.6 2017-06-20 16:25:18 +02:00
Trolli Schmittlauch 626ffdd4e2 clarify index j 2017-06-20 16:14:04 +02:00
14 changed files with 213 additions and 21 deletions

View file

@ -2,7 +2,7 @@
## Tooling
- Python 3.5
- Python 3.6
- [MyPy](http://www.mypy-lang.org/ ) für statische Typchecks
- [Pandoc](https://pandoc.org/ ) für die Dokumentation
- Python Module: siehe [requirements.txt](https://pip.pypa.io/en/latest/user_guide/#requirements-files )

23
Readme.txt Normal file
View file

@ -0,0 +1,23 @@
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 Normal file
View file

@ -0,0 +1,36 @@
## 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\}$
- indirekt lässt sich durch laufende Operation und Zeitpunkt auch Belegung einer Maschine zu einem Zeitpunkt ermitteln
- Optimierung: sparse speichern
1. Liste von (T, $o_j$) mit $T \in \mathbb{N}$ (Time), $o_j \in O$ (Tasks)
1. Liste von (T, $o_j$) mit $T \in \mathbb{N}$ (Time), $o_j \in O$ (Tasks), j bezeichnet den Job
- Operationen:
- Vertauschen von 2 Jobs auf einer Maschine, selbstinvers
- Verzögern von Operationen (keine expliziten Wartezustände nötig)

View file

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

3
shell.nix Normal file
View file

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

View file

View file

@ -39,6 +39,7 @@ def accept(solution):
random solution.
"""
return tighten(solution)
#return solution
def tighten(solution):

0
src/Output/__init__.py Normal file
View file

32
src/Output/output.py Normal file
View file

@ -0,0 +1,32 @@
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()

View file

@ -6,33 +6,33 @@ from collections.abc import Mapping
__all__ = ["js1_style", "js2_style"]
grammar = """
# starting point for jobshop1 input file
// starting point for jobshop1 input file
job_shop1 = skip_preface
# eat away lines of preface, until first problem_instance is
# encountered; then the list of instances start
// eat away lines of preface, until first problem_instance is
// encountered; then the list of instances start
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
problem_instance = trim_ws "instance" ' ' instance_name trim_ws eol trim_ws eol sep_line description eol problem_data
description = r"[^\n]*"
instance_name = r"\w+"
sep_line = trim_ws plus_line trim_ws eol
# lines out of multiple + signs
// lines out of multiple + signs
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
# entry point for jobshop2 input files
// entry point for jobshop2 input files
job_shop2 = problem_data EOF
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]*'
# 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"
nonneg_num = r'\d+'
num_jobs = nonneg_num
num_machines = nonneg_num
machine = nonneg_num
duration = nonneg_num
# task data for 1 job
// task data for 1 job
job_data = ' '* machine ' '+ duration (' '+ machine ' '+ duration)* trim_ws eol
"""

View file

View file

@ -1,7 +1,10 @@
INSTANCES = [(5, 5)]
TASKS = [[(1, 21), (0, 53), (4, 95), (3, 55), (2, 35)],
[(0, 21), (3, 52), (4, 16), (2, 26), (1, 71)],
[(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)]]
import Parser.js1_style as p
#import Parser.js2_style as p
from SchedulingAlgorithms import simanneal as sim
from Output import output as o
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)

View file

@ -1,6 +1,97 @@
#! /usr/bin/env python
def main() -> None:
pass
if "__name__" == "__main__":
import sys
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()