Compare commits

..

43 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 3a7a8ebcbd Somewhat sensible default parameters, temperature, amount of maximum anneal iterations and generator accept probability passed to anneal. 2017-07-12 04:23:36 +02:00
Maximilian Schlosser 991b7f4175 simulated annealing 2017-07-11 22:25:56 +02:00
Maximilian Schlosser 049e64c675 Magic number is now a default parameter 2017-07-11 13:55:02 +02:00
Maximilian Schlosser 32c99ff075 accept, tighten, generate rewrite (now has magic number describing percentage) 2017-07-11 13:50:51 +02:00
Maximilian Schlosser 304dc401f7 Added matplotlib as requirement 2017-07-11 13:18:14 +02:00
Maximilian Schlosser 6783d91c43 tighten 2017-07-11 12:07:03 +02:00
lukasstracke 6be2e20cc7 Pull_Fwd inkl. Rectify funktionstüchtig TODO: Accept + Simanneal + Output 2017-07-10 23:17:33 +02:00
Maximilian Schlosser a7f1a86748 Some small documentation, hopefully useful 2017-07-10 15:59:00 +02:00
Maximilian Schlosser 85e61f91fb Multiple methods for rectify, merge of mapping. TODO: rectify loop 2017-07-09 18:57:52 +02:00
Maximilian Schlosser 8ed9d800c3 Merge branch 'devel' into simanneal 2017-07-09 18:00:32 +02:00
Trolli Schmittlauch 7d330e9866 Merge branch 'mapping_problem' of PSSAI_Team/JobShopScheduling into devel 2017-07-09 17:20:50 +02:00
Maximilian Schlosser bd370a1ed5 Put docstrings at the right(?) positions. 2017-07-03 16:11:30 +02:00
Maximilian Schlosser a8c4a11b20 mock() to generate mockenv for the generator, pull_fwd() to compute new solutions. Rectify needs to be implemented before generator works. 2017-07-02 19:32:26 +02:00
Maximilian Schlosser 23e6d12754 enumerate tasks 2017-07-02 14:07:38 +02:00
Maximilian Schlosser 3aed7f52f5 Merge branch 'devel' into simanneal 2017-07-02 13:46:56 +02:00
Maximilian Schlosser e3945ce3dc solve by enumeration 2017-06-29 19:14:24 +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
17 changed files with 460 additions and 21 deletions

View file

@ -2,7 +2,7 @@
## Tooling ## Tooling
- Python 3.5 - Python 3.6
- [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 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

4
inputdata/sample Normal file
View file

@ -0,0 +1,4 @@
3 3
0 4 1 6 2 1
1 3 0 13 2 4
1 2 2 5 0 3

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) 1. Liste von (T, $o_j$) mit $T \in \mathbb{N}$ (Time), $o_j \in O$ (Tasks), j bezeichnet den Job
- 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,2 +1,5 @@
mypy 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

198
src/Generator/generator.py Normal file
View file

@ -0,0 +1,198 @@
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

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"] __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

View file

@ -0,0 +1,10 @@
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

View file

@ -0,0 +1,36 @@
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

View file

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

View file

@ -1,6 +1,97 @@
#! /usr/bin/env python #! /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() main()