2012-05-16 16:35:58 +00:00
|
|
|
#!/usr/bin/env python
|
|
|
|
#
|
|
|
|
# Copyright 2012 Johannes 'josch' Schauer <j.schauer@email.de>
|
|
|
|
#
|
|
|
|
# This file is part of Sisyphus.
|
|
|
|
#
|
|
|
|
# Sisyphus is free software: you can redistribute it and/or modify
|
|
|
|
# it under the terms of the GNU General Public License as published by
|
|
|
|
# the Free Software Foundation, either version 3 of the License, or
|
|
|
|
# (at your option) any later version.
|
|
|
|
#
|
|
|
|
# Sisyphus is distributed in the hope that it will be useful,
|
|
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
# GNU General Public License for more details.
|
|
|
|
#
|
|
|
|
# You should have received a copy of the GNU General Public License
|
|
|
|
# along with Sisyphus. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
|
2012-05-02 09:12:10 +00:00
|
|
|
import sys
|
|
|
|
import subprocess
|
|
|
|
import itertools
|
2012-05-15 22:59:30 +00:00
|
|
|
from util import dicttoxmlfile, get_packlist_dict, get_packlist_dict_multi, dicttoxmlstring, get_order_dict
|
2012-05-08 08:01:10 +00:00
|
|
|
from arrange_spread2 import arrange_in_layer
|
2012-05-02 09:12:10 +00:00
|
|
|
import cPickle
|
|
|
|
from binascii import a2b_base64
|
|
|
|
import tempfile
|
|
|
|
import os
|
2012-05-02 11:47:38 +00:00
|
|
|
import zlib
|
2012-05-03 08:34:46 +00:00
|
|
|
import fcntl
|
2012-05-15 01:24:24 +00:00
|
|
|
import ctypes
|
2012-05-16 05:49:58 +00:00
|
|
|
import random
|
2012-05-15 01:24:24 +00:00
|
|
|
|
|
|
|
libpallet = ctypes.cdll.LoadLibrary('./libpallet.so.0.0.0')
|
|
|
|
libpallet.evaluate.restype = ctypes.c_double
|
2012-05-02 09:12:10 +00:00
|
|
|
|
2012-05-15 14:47:08 +00:00
|
|
|
if os.environ.get("multi_pallet"):
|
2012-05-15 21:17:06 +00:00
|
|
|
try_multi_pallet = bool(int(os.environ["multi_pallet"]))
|
2012-05-15 14:47:08 +00:00
|
|
|
else:
|
2012-05-15 21:17:06 +00:00
|
|
|
try_multi_pallet = False
|
|
|
|
|
|
|
|
if os.environ.get("permutations"):
|
|
|
|
try_permutations = bool(int(os.environ["permutations"]))
|
|
|
|
else:
|
|
|
|
try_permutations = True
|
2012-05-15 14:47:08 +00:00
|
|
|
|
2012-05-16 05:49:58 +00:00
|
|
|
if os.environ.get("iterations"):
|
|
|
|
max_iter = int(os.environ["iterations"])
|
|
|
|
else:
|
|
|
|
max_iter = -1
|
|
|
|
|
|
|
|
if os.environ.get("randomize"):
|
|
|
|
try_random = bool(int(os.environ["randomize"]))
|
|
|
|
else:
|
|
|
|
try_random = False
|
|
|
|
|
2012-05-15 14:47:08 +00:00
|
|
|
def pack_single_pallet(permut_layers, rest_layers, pallet):
|
|
|
|
pack_sequence = 1
|
|
|
|
pack_height = 0
|
|
|
|
|
|
|
|
articles_to_pack = list()
|
|
|
|
|
2012-05-16 05:49:58 +00:00
|
|
|
for layer in permut_layers+rest_layers:
|
2012-05-15 14:47:08 +00:00
|
|
|
pack_height += layer[0]['Article']['Height']
|
|
|
|
#if pack_height > pallet['Dimensions']['MaxLoadHeight']:
|
|
|
|
# break
|
|
|
|
for article in layer:
|
|
|
|
article['PackSequence'] = pack_sequence
|
|
|
|
article['PlacePosition']['Z'] = pack_height
|
|
|
|
articles_to_pack.append(article)
|
|
|
|
pack_sequence += 1
|
|
|
|
|
|
|
|
return get_packlist_dict(pallet, articles_to_pack)
|
|
|
|
|
|
|
|
def pack_multi_pallet(permut_layers, rest_layers, pallet):
|
2012-05-16 05:49:58 +00:00
|
|
|
sum_all_article_height = sum([layer[0]['Article']['Height'] for layer in permut_layers+rest_layers])
|
2012-05-15 22:59:30 +00:00
|
|
|
|
|
|
|
number_of_pallets = int(sum_all_article_height/pallet['Dimensions']['MaxLoadHeight'])+1
|
|
|
|
|
|
|
|
article_lists = [ list() for i in range(number_of_pallets) ]
|
|
|
|
pack_heights = [ 0 for i in range(number_of_pallets) ]
|
|
|
|
pack_sequences = [ 1 for i in range(number_of_pallets) ]
|
|
|
|
|
|
|
|
# spread over pallets in order
|
2012-05-16 05:49:58 +00:00
|
|
|
for layer in permut_layers+rest_layers:
|
2012-05-15 22:59:30 +00:00
|
|
|
# select as current, the pallet with the lowest height
|
|
|
|
current_pallet = pack_heights.index(min(pack_heights))
|
|
|
|
pack_heights[current_pallet] += layer[0]['Article']['Height']
|
|
|
|
for article in layer:
|
|
|
|
article['PackSequence'] = pack_sequences[current_pallet]
|
|
|
|
article['PlacePosition']['Z'] = pack_heights[current_pallet]
|
|
|
|
article_lists[current_pallet].append(article)
|
|
|
|
pack_sequences[current_pallet] += 1
|
|
|
|
|
|
|
|
return get_packlist_dict_multi(pallet, article_lists)
|
2012-05-15 14:47:08 +00:00
|
|
|
|
|
|
|
def evaluate_single_pallet(packlist):
|
|
|
|
tmp_fh, tmp = tempfile.mkstemp()
|
|
|
|
dicttoxmlfile(packlist, tmp)
|
|
|
|
result = libpallet.evaluate(sys.argv[1], tmp, sys.argv[3])
|
|
|
|
os.close(tmp_fh)
|
|
|
|
os.remove(tmp)
|
|
|
|
return result
|
|
|
|
|
|
|
|
def evaluate_multi_pallet(packlist):
|
2012-05-15 22:59:30 +00:00
|
|
|
pallets = packlist['Response']['PackList']['PackPallets']['PackPallet']
|
|
|
|
|
|
|
|
article_lists = [ pallet['Packages']['Package'] for pallet in pallets ]
|
|
|
|
|
|
|
|
scores = list()
|
|
|
|
for pallet, articles_to_pack in zip(pallets, article_lists):
|
|
|
|
partial_packlist = get_packlist_dict(pallet, articles_to_pack)
|
|
|
|
tmp_fh, tmp = tempfile.mkstemp()
|
|
|
|
tmp_order_fh, tmp_order = tempfile.mkstemp()
|
|
|
|
dicttoxmlfile(partial_packlist, tmp)
|
|
|
|
dicttoxmlfile(get_order_dict(pallet, articles_to_pack), tmp_order)
|
|
|
|
scores.append(libpallet.evaluate(tmp_order, tmp, sys.argv[3]))
|
|
|
|
os.close(tmp_fh)
|
|
|
|
os.close(tmp_order_fh)
|
|
|
|
os.remove(tmp)
|
|
|
|
os.remove(tmp_order)
|
|
|
|
|
|
|
|
return sum(scores)/len(scores)
|
2012-05-15 14:47:08 +00:00
|
|
|
|
2012-05-15 14:57:51 +00:00
|
|
|
def evaluate_layers_rests(layers, rests, score_max, pallet, result_max):
|
2012-05-02 09:12:10 +00:00
|
|
|
rest_layers = list()
|
|
|
|
# sort rests by space they cover and move them to the center of the pile
|
|
|
|
# append them to the layer list
|
|
|
|
for rest in sorted(rests, key=lambda rest: sum([article['Article']['Length']*article['Article']['Width'] for article in rest]), reverse=True):
|
|
|
|
plength, pwidth = (pallet['Dimensions']['Length'], pallet['Dimensions']['Width'])
|
|
|
|
root, layer, rest = arrange_in_layer(rest, plength, pwidth)
|
|
|
|
|
|
|
|
com_x = 0
|
|
|
|
com_y = 0
|
2012-05-16 05:47:24 +00:00
|
|
|
leftmost = pallet['Dimensions']['Length']
|
|
|
|
rightmost = 0
|
|
|
|
bottommost = pallet['Dimensions']['Width']
|
|
|
|
topmost = 0
|
2012-05-02 09:12:10 +00:00
|
|
|
for article in layer:
|
|
|
|
com_x += article['PlacePosition']['X']
|
|
|
|
com_y += article['PlacePosition']['Y']
|
2012-05-16 05:47:24 +00:00
|
|
|
if article['PlacePosition']['X']-article['Article']['Length']/2 < leftmost:
|
|
|
|
leftmost = article['PlacePosition']['X']-article['Article']['Length']/2
|
|
|
|
if article['PlacePosition']['X']+article['Article']['Length']/2 > rightmost:
|
|
|
|
rightmost = article['PlacePosition']['X']+article['Article']['Length']/2
|
|
|
|
if article['PlacePosition']['Y']-article['Article']['Width']/2 < bottommost:
|
|
|
|
bottommost = article['PlacePosition']['Y']-article['Article']['Width']/2
|
|
|
|
if article['PlacePosition']['Y']+article['Article']['Width']/2 > topmost:
|
|
|
|
topmost = article['PlacePosition']['Y']+article['Article']['Width']/2
|
2012-05-02 09:12:10 +00:00
|
|
|
com_x, com_y = com_x/len(layer), com_y/len(layer)
|
|
|
|
|
2012-05-16 05:47:24 +00:00
|
|
|
llength = rightmost - leftmost
|
|
|
|
lwidth = topmost - bottommost
|
|
|
|
|
|
|
|
if com_x < llength-plength/2:
|
|
|
|
com_x = llength-plength/2
|
|
|
|
elif com_x > plength/2:
|
|
|
|
com_x = plength/2
|
|
|
|
if com_y < lwidth-pwidth/2:
|
|
|
|
com_y = lwidth-pwidth/2
|
|
|
|
elif com_y > pwidth/2:
|
|
|
|
com_y = pwidth/2
|
|
|
|
|
2012-05-02 09:12:10 +00:00
|
|
|
diff_x, diff_y = plength*0.5-com_x, pwidth*0.5-com_y
|
|
|
|
|
|
|
|
for article in layer:
|
|
|
|
article['PlacePosition']['X'] += diff_x
|
|
|
|
article['PlacePosition']['Y'] += diff_y
|
|
|
|
|
|
|
|
rest_layers.append(layer)
|
|
|
|
|
2012-05-15 21:17:06 +00:00
|
|
|
if try_permutations:
|
|
|
|
permutations = itertools.permutations(layers)
|
|
|
|
else:
|
2012-05-16 05:49:58 +00:00
|
|
|
#permutations = [tuple(sorted(layers, key=lambda layer: sum([article['Article']['Weight'] for article in layer]), reverse=True))]
|
|
|
|
#permutations = [tuple(sorted(layers, key=lambda layer: sum([article['Article']['Length']*article['Article']['Width'] for article in layer]), reverse=True))]
|
|
|
|
#permutations = (layers for i in xrange(1000))
|
|
|
|
permutations = [layers]
|
|
|
|
|
|
|
|
i = 0
|
2012-05-15 21:17:06 +00:00
|
|
|
for permut_layers in permutations:
|
2012-05-16 05:49:58 +00:00
|
|
|
permut_layers = list(permut_layers)
|
|
|
|
if try_random:
|
|
|
|
random.shuffle(permut_layers)
|
2012-05-15 21:17:06 +00:00
|
|
|
if try_multi_pallet:
|
2012-05-15 14:47:08 +00:00
|
|
|
packlist = pack_multi_pallet(permut_layers, rest_layers, pallet)
|
|
|
|
score = evaluate_multi_pallet(packlist)
|
|
|
|
else:
|
2012-05-16 05:49:58 +00:00
|
|
|
packlist = pack_single_pallet(permut_layers, rest_layers, pallet)
|
2012-05-15 14:47:08 +00:00
|
|
|
score = evaluate_single_pallet(packlist)
|
2012-05-16 05:49:58 +00:00
|
|
|
|
2012-05-15 14:57:51 +00:00
|
|
|
if score >= score_max[0]:
|
2012-05-08 08:01:10 +00:00
|
|
|
result_max[0] = dicttoxmlstring(packlist)
|
2012-05-15 14:57:51 +00:00
|
|
|
score_max[0] = score
|
2012-05-02 09:12:10 +00:00
|
|
|
|
2012-05-16 05:49:58 +00:00
|
|
|
i+=1
|
|
|
|
if max_iter != -1 and i >= max_iter:
|
|
|
|
break
|
|
|
|
|
2012-05-02 09:12:10 +00:00
|
|
|
def main():
|
2012-05-15 01:24:24 +00:00
|
|
|
if len(sys.argv) < 5:
|
|
|
|
print "usage:", sys.argv[0], "order.xml packlist.xml scoring.xml LAYER [LAYER..]"
|
2012-05-08 08:01:10 +00:00
|
|
|
exit(1)
|
|
|
|
|
2012-05-15 14:57:51 +00:00
|
|
|
score_max = [0]
|
2012-05-08 08:01:10 +00:00
|
|
|
result_max = [None]
|
2012-05-15 01:24:24 +00:00
|
|
|
for arg in sys.argv[4:]:
|
2012-05-02 11:47:38 +00:00
|
|
|
layers, rests, pallet = cPickle.loads(zlib.decompress(a2b_base64(arg)))
|
2012-05-15 14:57:51 +00:00
|
|
|
evaluate_layers_rests(layers, rests, score_max, pallet, result_max)
|
2012-05-02 09:12:10 +00:00
|
|
|
|
2012-05-15 14:57:51 +00:00
|
|
|
print score_max[0]
|
2012-05-02 09:12:10 +00:00
|
|
|
|
2012-05-08 08:01:10 +00:00
|
|
|
lock = open("score_max.lock", "w")
|
|
|
|
fcntl.lockf(lock, fcntl.LOCK_EX)
|
|
|
|
if os.path.isfile("score_max"):
|
|
|
|
with open("score_max", "r") as f:
|
2012-05-15 14:57:51 +00:00
|
|
|
score_max_f = float(f.read())
|
2012-05-08 08:01:10 +00:00
|
|
|
else:
|
2012-05-15 14:57:51 +00:00
|
|
|
score_max_f = 0.0
|
|
|
|
if score_max[0] > score_max_f:
|
2012-05-08 08:01:10 +00:00
|
|
|
with open(sys.argv[2], "w+") as f:
|
|
|
|
f.write(result_max[0])
|
|
|
|
with open("score_max", "w+") as f:
|
2012-05-15 14:57:51 +00:00
|
|
|
f.write(str(score_max[0]))
|
2012-05-08 08:01:10 +00:00
|
|
|
lock.close()
|
|
|
|
|
2012-05-02 09:12:10 +00:00
|
|
|
if __name__ == "__main__":
|
|
|
|
main()
|