From 22fdf9f98d500d72f23e7f3633f7f4ec2b0452e8 Mon Sep 17 00:00:00 2001 From: Philipp Obermeier Date: Thu, 22 Jun 2017 15:14:30 +0200 Subject: [PATCH 001/188] Added link to instances set --- docs/benchmarkset.org | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/benchmarkset.org b/docs/benchmarkset.org index 7c9c318..3ef6a22 100644 --- a/docs/benchmarkset.org +++ b/docs/benchmarkset.org @@ -68,8 +68,8 @@ #+END_SRC where the first parameter of split specifies the number of warehouses instances (here 5), and the second parameter the number of order instances (here 10) per each warehouse instance. - A precomputed set of the referential instances for invocation + A set of the referential instances generated by #+BEGIN_SRC shell python ./generator/test_instances.py -N 10 -d --split 10 10 #+END_SRC - can be found here (TODO!). + can be found in the latest [[https://github.com/potassco/asprilo/releases][ASPRILO release]]. From 831bc89f1fefd9389db8609ec05b14d542421510 Mon Sep 17 00:00:00 2001 From: Philipp Obermeier Date: Thu, 22 Jun 2017 16:00:13 +0200 Subject: [PATCH 002/188] Docs: fixed image links --- docs/img/example_inst.png | Bin 8843 -> 6500 bytes docs/specification.org | 16 ++++++++-------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/docs/img/example_inst.png b/docs/img/example_inst.png index 67c022975439854edcc20d92a8b4d7788689152c..eb9db830257dc6daf719179d07a3ded3977f6088 100644 GIT binary patch literal 6500 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 O0c@=tEKz5@?*9il%sb!! literal 8843 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 Date: Fri, 23 Jun 2017 15:57:12 +0200 Subject: [PATCH 003/188] Docs: fix visualizer requirements - Moved visualizer requirments documentation to correct location --- docs/visualizer.org | 109 ++++++++++++++++++++++++- visualizer/README.org | 1 + visualizer/{README.md => README_DE.md} | 0 visualizer/Requirements.org | 103 ----------------------- 4 files changed, 109 insertions(+), 104 deletions(-) create mode 120000 visualizer/README.org rename visualizer/{README.md => README_DE.md} (100%) delete mode 100644 visualizer/Requirements.org diff --git a/docs/visualizer.org b/docs/visualizer.org index b5b019f..67c34d1 100644 --- a/docs/visualizer.org +++ b/docs/visualizer.org @@ -15,4 +15,111 @@ ./visualizer/scripts/visualizer -h #+END_SRC - TODO: Detailed Readme + +* Requirements + +** Overview + + The visualizer requires the following software installed on your system: + + 1. [[http://github.com/potassco/clingo][clingo5]], version 5.3.0 or later + 2. [[http://www.python.org][Python interpreter version 2.7.x]] + 3. [[http://qt-project.org/qt5][Qt5]] + 4. [[http://pyqt.sourceforge.net/Docs/PyQt5/installation.html][PyQt5]], version 5.6 or later + + +** Building PyQt5 from Source Code + + We assume that python an Qt5 are already installed on your system. + +*** SIP Installation + +**** Download + + #+BEGIN_SRC shell + $ wget https://sourceforge.net/projects/pyqt/files/sip/sip-4.19.1/sip-4.19.1.tar.gz + $ tar -xzvf sip-4.19.1.tar.gz + #+END_SRC + +**** Configuration + + - In case you install sip system-wide, enter: + #+BEGIN_SRC shell + $ cd sip-4.19.1 + $ python configure.py + #+END_SRC + + - In case you are using a virtual environment, enter: + #+BEGIN_SRC shell + $ cd sip-4.19.1 + $ python configure.py --deployment-target=10.12 --destdir=${VIRTUAL_ENV}/lib/python2.7/site-packages --incdir=${VIRTUAL_ENV}/include/python2.7 + #+END_SRC + Make sure that the environment variable =VIRTUAL_ENV= is set to the path of your virtual python environment. + +**** Building and Installation + + #+BEGIN_SRC shell + $ make + $ make install + #+END_SRC + +*** PyQt5 Installation + +**** Download + + #+BEGIN_SRC shell + $ wget https://sourceforge.net/projects/pyqt/files/PyQt5/PyQt-5.8.1/PyQt5_gpl-5.8.1.tar.gz + $ tar -xzvf PyQt5_gpl-5.8.1.tar.gz + #+END_SRC + +**** Configuration + + - In case you install sip system-wide, enter: + #+BEGIN_SRC shell + $ cd PyQt5_gpl-5.8.1 + $ $ python configure.py --verbose + #+END_SRC + + - In case you are using a virtual environment, enter: + #+BEGIN_SRC shell + $ cd PyQt5_gpl-5.8.1 + $ $ python configure.py --sip=${VIRTUAL_ENV}/bin/sip --sip-incdir=${VIRTUAL_ENV}/include/python2.7/ --verbose + #+END_SRC + + For both cases, make sure that =qmake= is in your path. Alternatively, add + =--qmake== as additional argument to the invocation of the =configure.py= + script above. + +**** Building and Installation + + #+BEGIN_SRC shell + $ make + $ make install + #+END_SRC + + + + + + + + + + + + + + + + + + + + + + + + +* Usage + + TODO diff --git a/visualizer/README.org b/visualizer/README.org new file mode 120000 index 0000000..55089f6 --- /dev/null +++ b/visualizer/README.org @@ -0,0 +1 @@ +../docs/visualizer.org \ No newline at end of file diff --git a/visualizer/README.md b/visualizer/README_DE.md similarity index 100% rename from visualizer/README.md rename to visualizer/README_DE.md diff --git a/visualizer/Requirements.org b/visualizer/Requirements.org deleted file mode 100644 index f829615..0000000 --- a/visualizer/Requirements.org +++ /dev/null @@ -1,103 +0,0 @@ -#+TITLE: Requirements of Visualizer -#+AUTHOR: Philipp Obermeier -#+SETUPFILE: ~/tools/emacs/org-html-themes/setup/theme-readtheorg.setup - -* Overview - -The visualizer requires the following software installed on your system: - -1. [[http://github.com/potassco/clingo][clingo5]], version 5.1.0 or later -2. [[http://www.python.org][Python interpreter version 2.7.x]] -3. [[http://qt-project.org/qt5][Qt5]] -4. [[http://pyqt.sourceforge.net/Docs/PyQt5/installation.html][PyQt5]], version 5.6 or later - - -* Building PyQt5 from Source Code - - We assume that python an Qt5 are already installed on your system. - -** SIP Installation - -*** Download - - #+BEGIN_SRC shell - $ wget https://sourceforge.net/projects/pyqt/files/sip/sip-4.19.1/sip-4.19.1.tar.gz - $ tar -xzvf sip-4.19.1.tar.gz - #+END_SRC - -*** Configuration - - - In case you install sip system-wide, enter: - #+BEGIN_SRC shell - $ cd sip-4.19.1 - $ python configure.py - #+END_SRC - - - In case you are using a virtual environment, enter: - #+BEGIN_SRC shell - $ cd sip-4.19.1 - $ python configure.py --deployment-target=10.12 --destdir=${VIRTUAL_ENV}/lib/python2.7/site-packages --incdir=${VIRTUAL_ENV}/include/python2.7 - #+END_SRC - Make sure that the environment variable =VIRTUAL_ENV= is set to the path of your virtual python environment. - -*** Building and Installation - - #+BEGIN_SRC shell - $ make - $ make install - #+END_SRC - -** PyQt5 Installation - -*** Download - - #+BEGIN_SRC shell - $ wget https://sourceforge.net/projects/pyqt/files/PyQt5/PyQt-5.8.1/PyQt5_gpl-5.8.1.tar.gz - $ tar -xzvf PyQt5_gpl-5.8.1.tar.gz - #+END_SRC - -*** Configuration - - - In case you install sip system-wide, enter: - #+BEGIN_SRC shell - $ cd PyQt5_gpl-5.8.1 - $ $ python configure.py --verbose - #+END_SRC - - - In case you are using a virtual environment, enter: - #+BEGIN_SRC shell - $ cd PyQt5_gpl-5.8.1 - $ $ python configure.py --sip=${VIRTUAL_ENV}/bin/sip --sip-incdir=${VIRTUAL_ENV}/include/python2.7/ --verbose - #+END_SRC - - For both cases, make sure that =qmake= is in your path. Alternatively, add - =--qmake== as additional argument to the invocation of the =configure.py= - script above. - -*** Building and Installation - - #+BEGIN_SRC shell - $ make - $ make install - #+END_SRC - - - - - - - - - - - - - - - - - - - - - From b248490d3775cf2aad77a538854cc4313a9bb87a Mon Sep 17 00:00:00 2001 From: Philipp Obermeier Date: Mon, 26 Jun 2017 14:26:34 +0200 Subject: [PATCH 004/188] Generator: Fixes for clingo5.3, invoc. w/o args - Fix to adjust solve sig for clingo 5.3 - Fix to allow invocation w/o command line args --- generator/ig.py | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/generator/ig.py b/generator/ig.py index fc80390..d6716e6 100755 --- a/generator/ig.py +++ b/generator/ig.py @@ -202,7 +202,7 @@ def solve(self): # solve_future.cancel() # solve_result = solve_future.get() - solve_result = self._control.solve(self.on_model) + solve_result = self._control.solve(on_model=self.on_model) if not self._args.quiet: print "Parallel mode: " + str(self._control.configuration.solve.parallel_mode) @@ -371,9 +371,9 @@ def parse_cl_args(self): layout_args.add_argument("-B", "--beltway-layout", action="store_true", help="""a beltway in form of highway nodes along the edges of the warehouse""") - layout_args.add_argument("-X", "--cluster-x", type=int, + layout_args.add_argument("-X", "--cluster-x", type=int, default=2, help="the size of one rectangular shelf cluster in x-direction") - layout_args.add_argument("-Y", "--cluster-y", type=int, + layout_args.add_argument("-Y", "--cluster-y", type=int, default=2, help="the size of one rectangular shelf cluster in y-direction") project_args = parser.add_argument_group('projection and template options') project_args.add_argument("-T", "--template", nargs='*', type=str, default=[], @@ -406,12 +406,11 @@ def sig_handler(signum, frame): signal.signal(signal.SIGINT, sig_handler) signal.signal(signal.SIGALRM, sig_handler) - # igen = InstanceGenerator(cl_args) - + igen = InstanceGenerator(self._cl_args) try: - igen = InstanceGenerator(self._cl_args) signal.alarm(self._cl_args.wait) igen.solve() + return igen.dest_dirs except Exception as exc: if sig_handled[0]: pass @@ -420,8 +419,6 @@ def sig_handler(signum, frame): finally: igen.interrupt() - return igen.dest_dirs - def split_up_instances(self): num_wh_inst, num_order_inst = self._cl_args.split parser = argparse.ArgumentParser() From 56f0beb8770d3f5b7adbae80cff7de01f939070e Mon Sep 17 00:00:00 2001 From: Philipp Obermeier Date: Mon, 26 Jun 2017 14:36:00 +0200 Subject: [PATCH 005/188] Fixed generator's load path to encoding --- generator/ig.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/generator/ig.py b/generator/ig.py index d6716e6..ea5000f 100755 --- a/generator/ig.py +++ b/generator/ig.py @@ -125,7 +125,7 @@ def solve(self): # print "Used args for solving: " + str(self._args) self._control = clingo.Control(self._solve_opts) - self._control.load("ig.lp") + self._control.load(os.path.join(os.path.dirname(os.path.realpath(__file__)), 'ig.lp')) for template in self._args.template: self._control.load(template) self._control.ground([("base", [])]) From b3f6c6ab0ff06cb8c7ef093a1588ba103ebdf548 Mon Sep 17 00:00:00 2001 From: Philipp Obermeier Date: Mon, 26 Jun 2017 16:05:46 +0200 Subject: [PATCH 006/188] Updated changelog. --- CHANGES.org | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/CHANGES.org b/CHANGES.org index 33bc801..7ab7595 100644 --- a/CHANGES.org +++ b/CHANGES.org @@ -1,11 +1,14 @@ #+TITLE: Changelog -* 0.1.0 - - Initial Release - +* Unreleased +** Fixed + - Fix incorrect links and missing images in documentation + - Fix generator exception for invocation w/o arguments + - Fix generator solve calls to work with clingo 5.3 API +* 0.1.0 + Initial Release From 3592ba3c138359afa331ccd16a722cd59a9d2a77 Mon Sep 17 00:00:00 2001 From: Thomas-Otto Date: Wed, 28 Jun 2017 01:40:48 +0200 Subject: [PATCH 007/188] updated clingo interfaces updated piping: -it is now possible to pipe solutions directly from clingo *the encoding should conatin a #show init/2 and a #show occurs/3 statement -it will now print 'satisfiable' or 'unsatisfiable' to the console when getting input via piping -the visualizer now starts first and then waits non-blocking for pipe input config files will now be written to scripts/config few gui improvements bugfixes --- visualizer/scripts/encodings/encoding.lp | 2 + visualizer/scripts/network.py | 42 ++-- visualizer/scripts/solver.py | 4 +- visualizer/scripts/solver_inc.py | 4 +- visualizer/scripts/solver_interactive.py | 2 +- visualizer/scripts/visualizer | 75 ++++-- visualizer/visualizer/configuration.py | 34 +-- visualizer/visualizer/gui.py | 219 ++++++++++++------ visualizer/visualizer/model.py | 5 +- visualizer/visualizer/modelView.py | 16 +- visualizer/visualizer/network.py | 30 ++- visualizer/visualizer/parser.py | 4 +- .../visualizer/visualizerGraphicItem.py | 20 +- 13 files changed, 292 insertions(+), 165 deletions(-) diff --git a/visualizer/scripts/encodings/encoding.lp b/visualizer/scripts/encodings/encoding.lp index 29e22c1..7e00bb2 100755 --- a/visualizer/scripts/encodings/encoding.lp +++ b/visualizer/scripts/encodings/encoding.lp @@ -45,6 +45,7 @@ #const imin = 0. #const imax = 50. +#include . #program base. %% ACTIONS @@ -202,3 +203,4 @@ goal(t) :- not holds(request(_,_,_,_),t). %--------------------------------------------------% #show occurs/3. +#show init/2. diff --git a/visualizer/scripts/network.py b/visualizer/scripts/network.py index 9d67a58..80a1109 100644 --- a/visualizer/scripts/network.py +++ b/visualizer/scripts/network.py @@ -3,7 +3,7 @@ import socket import clingo -VERSION = '0.1.0' +VERSION = '0.1.1' class Network(object): def __init__(self): @@ -44,22 +44,25 @@ def is_ready_to_read(self, time_out = 0.1): def receive(self, time_out): if self._connection is None: - return '' - if self.is_ready_to_read(4.0): - while True: - new_data = self._connection.recv(2048) - if not new_data or new_data == '': - self.close() - return '' - self._raw_data += new_data - if not new_data.find('\n') == -1: - self.on_raw_data(self._raw_data) - return - - elif self._raw_data is not '': - return self._raw_data - else: - return None + return -1 + try: + if self.is_ready_to_read(4.0): + while True: + new_data = self._connection.recv(2048) + if not new_data or new_data == '': + self.close() + return 1 + self._raw_data += new_data + if not new_data.find('\n') == -1: + self.on_raw_data(self._raw_data) + return 0 + else: + return 0 + + except socket.error as error: + self._close() + print error + return -1 def send(self, data): if self._connection is None: @@ -93,13 +96,14 @@ def close(self): self._socket = None def run(self): + print 'Start ' + self._name self.connect() while(True): - if self.receive(1.0) is '': + if self.receive(1.0) != 0: return def on_control_symbol(self, symbol): - if symbol.name == 'RESET': + if symbol.name == 'reset': self._reset = True self._to_send = {} self._data = [] diff --git a/visualizer/scripts/solver.py b/visualizer/scripts/solver.py index 5a3309a..3f31d50 100755 --- a/visualizer/scripts/solver.py +++ b/visualizer/scripts/solver.py @@ -2,7 +2,7 @@ from network import * import os -VERSION = '0.1.0' +VERSION = '0.1.1' class Solver(Network): def __init__(self): @@ -30,7 +30,7 @@ def on_data(self, data): def solve(self): self._control.load(os.path.dirname(os.path.abspath(__file__)) + '/encodings/encoding.lp') self._control.ground([('base', [])]) - solve_future = self._control.solve_async(self.on_model) + solve_future = self._control.solve(on_model = self.on_model, async = True) while(True): if self.is_ready_to_read(): solve_future.cancel() diff --git a/visualizer/scripts/solver_inc.py b/visualizer/scripts/solver_inc.py index 3f0bd4b..28d055b 100755 --- a/visualizer/scripts/solver_inc.py +++ b/visualizer/scripts/solver_inc.py @@ -1,7 +1,7 @@ #! /usr/bin/env python from solver import * -VERSION = '0.1.0' +VERSION = '0.1.1' class Incremental_Solver(Solver): def __init__(self): @@ -22,7 +22,7 @@ def solve(self): self._control.assign_external(clingo.Function('query', [step]), True) print 'solve: ' + str(step) - solve_future = self._control.solve_async(self.on_model) + solve_future = self._control.solve(on_model = self.on_model, async = True) while(True): if self.is_ready_to_read(): solve_future.cancel() diff --git a/visualizer/scripts/solver_interactive.py b/visualizer/scripts/solver_interactive.py index 552afe0..931b7b0 100755 --- a/visualizer/scripts/solver_interactive.py +++ b/visualizer/scripts/solver_interactive.py @@ -1,7 +1,7 @@ #! /usr/bin/env python from solver_inc import * -VERSION = '0.1.0' +VERSION = '0.1.1' class Interactive_Solver(Incremental_Solver): def __init__(self): diff --git a/visualizer/scripts/visualizer b/visualizer/scripts/visualizer index bc55578..54ecc84 100755 --- a/visualizer/scripts/visualizer +++ b/visualizer/scripts/visualizer @@ -1,7 +1,7 @@ #! /usr/bin/env python import sys import os -sys.path.append(os.path.join(os.path.dirname(os.path.realpath(__file__)), '..')) +sys.path.append(os.path.dirname(os.path.abspath(__file__)) + '/..') import time import argparse from PyQt5.QtCore import * @@ -13,7 +13,7 @@ from visualizer.network import * from visualizer.gui import * from visualizer.configuration import * -VERSION = '0.10.2' +VERSION = '0.10.3' class VisualizerWindow(QMainWindow): def __init__(self): @@ -22,7 +22,7 @@ class VisualizerWindow(QMainWindow): self._argument_parser = argparse.ArgumentParser() self._argument_parser.add_argument('-d', '--directory', help='directory to load all instances from', - type=str, default = '/') + type=str) self._argument_parser.add_argument('-t', '--templates', help='loads files at the start', nargs='+', @@ -37,7 +37,7 @@ class VisualizerWindow(QMainWindow): type=str, default = '') self._argument_parser.add_argument('-m', '--mode', help='loads a preset of low level settings', - choices=['gtapf','aspilro'], + choices=['gtapf','asprilo'], type=str, default = '') self._argument_parser.add_argument('-s', '--start_solver', help='starts the default solver in the init file', @@ -65,18 +65,29 @@ class VisualizerWindow(QMainWindow): self._init_gui() self._asp_parser.set_model_view(self._model_view) - self.read_input() + + self._input_timer = QTimer() + self._input_timer.timeout.connect(self.read_input) + self._input_timer.start(1000) def _init_gui(self): self._splitter = QSplitter() self.setCentralWidget(self._splitter) - self._instance_file_browser = InstanceFileBrowser(self._args.directory) + directory = self._args.directory + if directory is None: + directory= os.getcwd() + + self._instance_file_browser = InstanceFileBrowser(directory) self._instance_file_browser.set_parser(self._asp_parser) self._splitter.addWidget(self._instance_file_browser) - if self._args.directory == '/': + if self._args.directory is None: self._instance_file_browser.setVisible(False) + self._file_dialog = QFileDialog(self, 'Open file', + directory, + 'Lp files (*.lp);; All files (*)') + self._model_view = ModelView() self._model_view.set_model(self._model) self._splitter.addWidget(self._model_view) @@ -132,13 +143,6 @@ class VisualizerWindow(QMainWindow): self.move(0,0) self.show() - directory = self._args.directory - if directory == '/': - directory= os.getcwd() - self._file_dialog = QFileDialog(self, 'Open file', - directory, - 'Lp files (*.lp);; All files (*)') - if self._args.start_solver: self._init_solver_dialog.on_ok(None) @@ -175,9 +179,9 @@ class VisualizerWindow(QMainWindow): menu_file.addAction(action) self.addAction(action) - action = QAction('Visualize answer', self) + action = QAction('Load plan', self) action.setShortcut('Ctrl+V') - action.setStatusTip('Load an answer file') + action.setStatusTip('Load a plan file') action.triggered.connect(lambda: (self.open_file_dialog(QFileDialog.AcceptOpen, self.load_answer))) @@ -190,13 +194,12 @@ class VisualizerWindow(QMainWindow): action.triggered.connect(lambda: (self.open_file_dialog(QFileDialog.AcceptSave, self.save_instance))) - action.triggered.connect(self.save_instance) menu_file.addAction(action) self.addAction(action) - action = QAction('Save answer', self) + action = QAction('Save plan', self) action.setShortcut('Ctrl+A') - action.setStatusTip('Saves the current answer to a file') + action.setStatusTip('Saves the current plan to a file') action.triggered.connect(lambda: (self.open_file_dialog(QFileDialog.AcceptSave, self.save_answer))) @@ -311,10 +314,34 @@ class VisualizerWindow(QMainWindow): self.addAction(action) def read_input(self): - if sys.stdin in select.select([sys.stdin], [], [], 0)[0]: - for line in sys.stdin: - self._asp_parser.add_program('input', line) - self._asp_parser.parse() + answer = False + found_answer = False + lines = [] + try: + if sys.stdin in select.select([sys.stdin], [], [], 0)[0]: + for line in sys.stdin.readlines(): + lines.append(line) + if answer and not found_answer: + self._asp_parser.add_program('input', line.replace(' ', '.')) + if line[len(line) - 1] == '\n': + answer = False + found_answer = True + self._asp_parser.add_program('input', '.') + self._asp_parser.parse() + if line.lower().find('answer') != -1: + print 'satisfiable' + answer = True + if line.lower().find('unsatisfiable') != -1: + print 'unsatisfiable' + anser = True + found_answer = True + if found_answer == False and len(lines) > 0: + for line in lines: + self._asp_parser.add_program('input', line) + self._asp_parser.parse() + except Exception as error: + print error + print 'Failed to read from stdin' def open_file_dialog(self, mode, function): self._file_dialog.setAcceptMode(mode) @@ -352,7 +379,7 @@ class VisualizerWindow(QMainWindow): for file_name in os.listdir(directory): full_file_name = directory + '/' + file_name if file_name.endswith('.lp'): - self._asp_parser.load_instance(full_file_name) + self._asp_parser.load_instance(full_file_name, create_png = True) elif os.path.isdir(full_file_name): self.create_pictures_in_directory(full_file_name) diff --git a/visualizer/visualizer/configuration.py b/visualizer/visualizer/configuration.py index 99a84a5..b626c50 100644 --- a/visualizer/visualizer/configuration.py +++ b/visualizer/visualizer/configuration.py @@ -3,6 +3,7 @@ from PyQt5.QtWidgets import * from PyQt5.QtGui import * import os +import sys class ConfigEntry(object): def __init__(self, read_value, default_value, to_string, display_name = None): @@ -18,7 +19,7 @@ def __init__(self, args = None): self._scroll_area = None self._widget = None self._text_edits = [] - self._file_name = 'config/init.cfg' + self._file_name = os.path.dirname(sys.argv[0]) + '/config/init.cfg' self._values = {} self.init_defaults() @@ -48,10 +49,10 @@ def init_defaults(self, args = None): ('network', 'port_simulator') : ConfigEntry(self._read_str_from_config, '5001', str, 'simulator port'), ('network', 'host_simulator') : ConfigEntry(self._read_str_from_config, '127.0.0.1', str, 'simulator host'), ('network', 'command_line_solver') : ConfigEntry(self._read_str_from_config, - './solver_inc.py --port 5000', str, + '__dir__/solver_inc.py --port 5000', str, 'solver command line'), - ('network', 'command_line_simulator') : ConfigEntry(self._read_str_from_config, - './simulator.py --port 5001', str, + ('network', 'command_line_simulator') : ConfigEntry(self._read_str_from_config, + '__dir__/simulator.py --port 5001', str, 'simulator command line'), ('visualizer', 'step_time') : ConfigEntry(self._read_int_from_config, 1200, str, 'step time'), ('visualizer', 'auto_solve') : ConfigEntry(self._read_bool_from_config, False, str, 'auto solving'), @@ -61,8 +62,8 @@ def init_defaults(self, args = None): self.read_file() def read_file(self): - if not os.path.isdir('config'): - os.makedirs('config') + if not os.path.isdir(os.path.dirname(sys.argv[0]) + '/config'): + os.makedirs(os.path.dirname(sys.argv[0]) + '/config') for key in self._values: if not self._config_parser.has_section(key[0]): self._config_parser.add_section(key[0]) @@ -144,6 +145,7 @@ def create_widget(self): self._scroll_area = QScrollArea() self._widget = QWidget() self._widget.setWindowTitle('Settings') + self._scroll_area.setWindowTitle('Settings') self._scroll_area.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOn) self._scroll_area.setWidget(self._widget) @@ -159,13 +161,13 @@ def create_widget(self): else: text.setText(entry.display_name + ': ') text.setReadOnly(True) - text.resize(200, 30) + text.resize(240, 30) text.move(0,y) value_text = QLineEdit(self._widget) value_text.setText(self._config_parser.get(section, option)) - value_text.resize(200, 30) - value_text.move(210,y) + value_text.resize(240, 30) + value_text.move(250,y) self._text_edits.append(value_text) y += 35 @@ -177,6 +179,8 @@ def create_widget(self): cancel_button.clicked.connect(self.on_cancel) cancel_button.move(140,y) self._widget.adjustSize() + self._scroll_area.adjustSize() + self._scroll_area.setFixedWidth(self._scroll_area.width()) def show_widget(self): if self._scroll_area is None: @@ -207,7 +211,7 @@ def __init__(self): def init_defaults(self, args = None): if args is None: - self._file_name = 'config/mdefault.cfg' + self._file_name = os.path.dirname(sys.argv[0]) + '/config/mdefault.cfg' self._values = { ('features', 'orders') : ConfigEntry(self._read_bool_from_config, True, str, 'orders'), ('features', 'products') : ConfigEntry(self._read_bool_from_config, True, str, 'products'), @@ -215,8 +219,8 @@ def init_defaults(self, args = None): ('features', 'debug') : ConfigEntry(self._read_bool_from_config, False, str, 'debug'), ('features', 'load_files') : ConfigEntry(self._read_str_from_config, '', str, 'load files'), } - elif args.mode == 'aspilro': - self._file_name = 'config/maspilro.cfg' + elif args.mode == 'asprilo': + self._file_name = os.path.dirname(sys.argv[0]) + '/config/masprilo.cfg' self._values = { ('features', 'orders') : ConfigEntry(self._read_bool_from_config, True, str, 'orders'), ('features', 'products') : ConfigEntry(self._read_bool_from_config, True, str, 'products'), @@ -225,13 +229,15 @@ def init_defaults(self, args = None): ('features', 'load_files') : ConfigEntry(self._read_str_from_config, '', str, 'load files'), } elif args.mode == 'gtapf': - self._file_name = 'config/mgtapf.cfg' + self._file_name = os.path.dirname(sys.argv[0]) + '/config/mgtapf.cfg' self._values = { ('features', 'orders') : ConfigEntry(self._read_bool_from_config, False, str, 'orders'), ('features', 'products') : ConfigEntry(self._read_bool_from_config, False, str, 'products'), ('features', 'tasks') : ConfigEntry(self._read_bool_from_config, True, str, 'tasks'), ('features', 'debug') : ConfigEntry(self._read_bool_from_config, False, str, 'debug'), - ('features', 'load_files') : ConfigEntry(self._read_str_from_config, './encodings/converter.lp', str, 'load files'), + ('features', 'load_files') : ConfigEntry(self._read_str_from_config, + os.path.dirname(sys.argv[0]) + '/encodings/converter.lp', + str, 'load files'), } elif args.debug: self.set_value('features', 'debug', True) diff --git a/visualizer/visualizer/gui.py b/visualizer/visualizer/gui.py index f5b3b7c..a68b277 100644 --- a/visualizer/visualizer/gui.py +++ b/visualizer/visualizer/gui.py @@ -1,8 +1,9 @@ from PyQt5.QtCore import * from PyQt5.QtWidgets import * from PyQt5.QtGui import * -import os import configuration +import os +import sys class InstanceFileBrowser(QTreeView): def __init__(self, directory = None): @@ -30,8 +31,8 @@ def _load_selected(self, clear = True, clear_actions = False, ground = True): if clear and ground: self._parser.load_instance(self._model.filePath(indexes[0])) elif ground: - self._parser.parse_file(self._model.filePath(indexes[0]), - clear = clear, + self._parser.parse_file(self._model.filePath(indexes[0]), + clear = clear, clear_actions = clear_actions) else: self._parser.load(self._model.filePath(indexes[0])) @@ -50,7 +51,7 @@ def mouseDoubleClickEvent (self, event): def keyPressEvent (self, event): if event.key() == Qt.Key_Return: - load_selected() + self._load_selected() return super(self.__class__, self).keyPressEvent(event) def contextMenuEvent(self, event): @@ -61,8 +62,8 @@ def contextMenuEvent(self, event): action.triggered.connect(lambda: self._load_selected(clear = True, clear_actions = False, ground = True)) self._menu.addAction(action) - action = QAction('load answer', self) - action.setStatusTip('Load the selected answer. Delete actions but keeps the model.') + action = QAction('load plan', self) + action.setStatusTip('Load the selected plan. Delete actions but keeps the model.') action.triggered.connect(lambda: self._load_selected(clear = False, clear_actions = True, ground = True)) self._menu.addAction(action) @@ -75,47 +76,101 @@ def contextMenuEvent(self, event): action.setStatusTip('Load the selected file and add it to the parser. Adds nothing to the current model.') action.triggered.connect(lambda: self._load_selected(clear = False, clear_actions = False, ground = False)) self._menu.addAction(action) - + self._menu.popup(self.mapToGlobal(QPoint(event.x(),event.y()))) def set_parser(self, parser): self._parser = parser -class ControlWidget(QWidget): +class TimestepWidget(QTextEdit): def __init__(self): super(self.__class__, self).__init__() - self._model_view = None - self._timestep_widget = QTextEdit(self) - self._timestep_widget.setReadOnly(True) - self._timestep_widget.resize(self.size().width(), 165) + self.setReadOnly(True) - self.create_button('<', (20, 50), self.on_undo, Qt.Key_Down) - self.create_button('>', (100, 50), self.on_update, Qt.Key_Up) - self._pause_button = self.create_button('|>', (60, 50), - self.on_pause, - Qt.Key_Space)[0] + def set_model_view(self, model_view): + self._model_view = model_view + self._model_view.get_model().add_window(self) + self.update() - self.create_button('|<|<', (20, 90), lambda: self.on_speed_up(-0.1), Qt.Key_Left) - self.create_button('|>|>', (60, 90), lambda: self.on_speed_up(0.1), Qt.Key_Right) - self.create_button('|<', (100, 90), self.on_restart, None) - self.create_button('>|', (140, 90), self.on_skip_to_end, None) + def resizeEvent(self, event): + font_size = min(event.size().width() / 12, event.size().height() / 2) + if font_size > 20: + font_size = 20 + elif font_size < 1: + font_size = 1 + self.setFontPointSize(font_size) + self.update() + super(self.__class__, self).resizeEvent(event) - self.create_button('+', (20, 130), lambda: self.on_zoom(100), Qt.Key_Plus) - self.create_button('-', (60, 130), lambda: self.on_zoom(-100), Qt.Key_Minus) + def update(self): + if self._model_view is None: + return + if self._model_view.get_model() is None: + return + step = self._model_view.get_model().get_current_step() + speed_up = 1/self._model_view.get_timer_speedup() + self.setText('current step: ' + + str(step) + + '\nspeed: ' + + '%.2f' % speed_up) + super(self.__class__, self).update() +class ControlWidget(QWidget): + def __init__(self): + super(self.__class__, self).__init__() - def create_button(self, name, pos, function, shortcut): + self._model_view = None + self._timestep_widget = None + self.create_button('<', (20, 0), + self.on_undo, Qt.Key_Down, + 'Do one step\n[Down]') + self.create_button('>', (100, 0), + self.on_update, Qt.Key_Up, + 'Undo one step\n[Up]') + self._pause_button = self.create_button('|>', (60, 0), + self.on_pause, + Qt.Key_Space, + 'Pause/Unpause the visualisation\n[Space]')[0] + + self.create_button('|<|<', (20, 35), + lambda: self.on_speed_up(-0.1), + Qt.Key_Left, + 'Slow down the visualisation\n[Right]') + self.create_button('|>|>', (60, 35), + lambda: self.on_speed_up(0.0909), + Qt.Key_Right, + 'Speed up the visualisation\n[Left]') + self.create_button('|<', (100, 35), + self.on_restart, None, + 'Restart the visualisation') + self.create_button('>|', (140, 35), + self.on_skip_to_end, None, + 'Skip to the end of the visualisation') + + self.create_button('+', (20, 75), + lambda: self.on_zoom(100), + Qt.Key_Plus, + 'Zoom in\n[+]') + self.create_button('-', (60, 75), + lambda: self.on_zoom(-100), + Qt.Key_Minus, + 'Zoom out\n[-]') + self.setFixedHeight(105) + + def create_button(self, name, pos, function, shortcut, tooltip = None): button = QPushButton(name, self) button.move(pos[0], pos[1]) button.resize(30,30) button.clicked.connect(function) + if tooltip is not None: + button.setToolTip(tooltip) action = None if shortcut is not None: action = QAction(self) action.setShortcut(shortcut) - action.setShortcutContext(Qt.ApplicationShortcut) + action.setShortcutContext(Qt.ApplicationShortcut) action.triggered.connect(function) self.addAction(action) return (button, action) @@ -125,6 +180,9 @@ def set_model_view(self, model_view): self._model_view.get_model().add_window(self) self.update() + def set_timestep_widget(self, timestep_widget): + self._timestep_widget = timestep_widget + def on_update(self, event = None): if self._model_view is not None: self._model_view.stop_timer() @@ -134,7 +192,7 @@ def on_pause(self, event = None): if self._model_view is not None: self._model_view.switch_timer() self.update() - + def on_undo(self, event = None): if self._model_view is not None: self._model_view.stop_timer() @@ -143,6 +201,7 @@ def on_undo(self, event = None): def on_speed_up(self, speed_up): if self._model_view is not None: self._model_view.speed_up_timer(speed_up) + self._timestep_widget.update() def on_restart(self): if self._model_view is not None: @@ -157,15 +216,10 @@ def on_zoom(self, zoom): self._model_view.zoom_event(zoom) def resizeEvent(self, event): - font_size = event.size().width() / 14 - if font_size > 20: - font_size = 20 - self._timestep_widget.setFontPointSize(font_size) - self._timestep_widget.setText(self._timestep_widget.toPlainText()) super(self.__class__, self).resizeEvent(event) def update(self): - if self._model_view is None: + if self._model_view is None: return if self._model_view.get_model() is None: return @@ -173,12 +227,10 @@ def update(self): self._pause_button.setText('|>') else: self._pause_button.setText('||') - step = self._model_view.get_model().get_current_step() - self._timestep_widget.setText('current step: ' + str(step)) super(self.__class__, self).update() class OccursWidget(QTextEdit): - def __init__(self): + def __init__(self): super(self.__class__, self).__init__() self._model = None self.setReadOnly(True) @@ -221,22 +273,26 @@ def set_model(self, model): class ControlSplitter(QSplitter): def __init__(self): super(self.__class__, self).__init__(Qt.Vertical) + self._timestep_widget = TimestepWidget() self._control_widget = ControlWidget() self._occurs_widget = OccursWidget() + self.addWidget(self._timestep_widget) self.addWidget(self._control_widget) self.addWidget(self._occurs_widget) - self.setSizes([165, self.size().height() - 165]) + self._control_widget.set_timestep_widget(self._timestep_widget) + self.setSizes([40, 105, self.size().height() - 145]) def set_model_view(self, model_view): + self._timestep_widget.set_model_view(model_view) self._control_widget.set_model_view(model_view) def set_model(self, model): - self._occurs_widget.set_model(model) + self._occurs_widget.set_model(model) class ServerDialog(QWidget): def __init__(self, title, host, port, socket): super(ServerDialog, self).__init__() - + self._socket = socket self.setWindowTitle(title) @@ -274,7 +330,7 @@ def set_address(self, host, port): def on_ok(self, event = None): try: - if (self._socket.connect(self._host_textbox.text(), + if (self._socket.connect(self._host_textbox.text(), int(self._port_textbox.text())) < 0): return self._socket.run() @@ -318,7 +374,8 @@ def __init__(self, socket_name, command, port, socket): def on_ok(self, event): self.hide() try: - self._socket.run_script(self._textbox.text(), + self._socket.run_script( + self._textbox.text().replace('__dir__', os.path.dirname(sys.argv[0])), int(self._port_textbox.text())) except(ValueError): print 'the port must be an integer value' @@ -328,7 +385,7 @@ def on_cancel(self, event): class GridSizeDialog(QWidget): def __init__(self): super(self.__class__, self).__init__() - + self._model = None self.model_view = None self._item_window = None @@ -360,7 +417,7 @@ def __init__(self): self._height_textbox.move(140,40) self._ok_button.move(20,80) self._cancel_button.move(140,80) - + def set_model(self, model): self._model = model @@ -371,7 +428,7 @@ def on_ok(self, event): self.hide() if self._model is None: return - if not self._model.get_editable(): + if not self._model.get_editable(): return try: self._model.set_grid_size(int(self._width_textbox.text()), int(self._height_textbox.text())) @@ -387,7 +444,7 @@ def on_cancel(self, event): class OrderDialog(QWidget): def __init__(self): super(self.__class__, self).__init__() - + self._model = None self.setWindowTitle('Add order') self.setFixedSize(280, 190) @@ -441,24 +498,24 @@ def __init__(self): def on_ok(self, event): if self._model is None: - return + return try: order = self._model.get_item(item_kind = 'order', ID = self._id_textbox.text(), - create = True, + create = True, add_immediately = self._model.get_editable()) if not self._model.get_editable() and self._model.contains(order): print 'commited orders can not be edited' else: order.set_station_id(self._ps_textbox.text()) - order.add_request(self._product_id_textbox.text(), + order.add_request(self._product_id_textbox.text(), int(self._product_amount_textbox.text())) self._model.update_windows() except: print 'failed to add new request' return self.hide() - + def on_cancel(self, event): self.hide() @@ -466,7 +523,7 @@ def set_model(self, model): self._model = model class OrderTable(QTableWidget): - def __init__(self, parent): + def __init__(self, parent): super(self.__class__, self).__init__(parent) self._model = None self.setColumnCount(6) @@ -499,7 +556,7 @@ def contextMenuEvent(self, event): if count <= row: for order2 in self._model.filter_items( item_kind = 'order', - return_non_buffered = False, + return_non_buffered = False, return_buffered = True): if count <= row: for request2 in order2.iterate_requests(): @@ -521,7 +578,7 @@ def contextMenuEvent(self, event): action.setShortcut('Ctrl + R') action.setStatusTip('Removes the selected request') action.triggered.connect(lambda: self.remove_request(order, request.product_id)) - self._menu.addAction(action) + self._menu.addAction(action) if order is not None: action = QAction('remove order', self) @@ -556,7 +613,7 @@ def remove_request(self, order, product_id): self._model.update_windows() class OrderWidget(QSplitter): - def __init__(self): + def __init__(self): super(self.__class__, self).__init__(Qt.Vertical) self._model = None self._table = OrderTable(self) @@ -581,8 +638,8 @@ def __init__(self): def update(self): self._deliver_widget.clear() orders = self._model.filter_items(item_kind = 'order') - orders2 = self._model.filter_items(item_kind = 'order', - return_non_buffered = False, + orders2 = self._model.filter_items(item_kind = 'order', + return_non_buffered = False, return_buffered = True) for order in orders: for ss in order.to_delivered_str(): @@ -672,7 +729,7 @@ def on_discard(self): class ProductDialog(QWidget): def __init__(self): super(self.__class__, self).__init__() - + self._shelf = None self._product_window = None self.setWindowTitle('Add product') @@ -703,7 +760,7 @@ def __init__(self): self._count_textbox.move(140,40) self._ok_button.move(20,80) self._cancel_button.move(140,80) - + def set_shelf(self, shelf): self._shelf = shelf @@ -726,7 +783,8 @@ def on_cancel(self, event): class ProductWindow(QTreeWidget): def __init__(self): #init item window super(self.__class__, self).__init__() - self._model = None + self._model = None + self.setWindowTitle('Products') self.setContextMenuPolicy(Qt.DefaultContextMenu) self._menu = QMenu() @@ -734,6 +792,7 @@ def __init__(self): #init item window self._product_dialog = ProductDialog() self._product_dialog.set_product_window(self) self.setHeaderLabels(['product ID', 'count', 'removed']) + self.resize(400, 200) def set_model(self, model): self._model = model @@ -742,7 +801,7 @@ def set_model(self, model): self._model.add_window(self) def update(self): - if self._model == None: + if self._model == None: return expanded_items = [] for ii in range(0, self.topLevelItemCount()): @@ -767,10 +826,10 @@ def show(self): def contextMenuEvent(self, event): - if not self._model.get_editable(): - return + if not self._model.get_editable(): + return item = self.itemAt(event.x(),event.y()) - if item is None: + if item is None: return parent = item.parent() @@ -781,7 +840,7 @@ def contextMenuEvent(self, event): shelf_index = self.indexOfTopLevelItem(item) else: shelf_index = self.indexOfTopLevelItem(parent) - + #get the shelf count = 0 for shelf2 in self._model.filter_items(item_kind = 'shelf'): @@ -807,13 +866,13 @@ def contextMenuEvent(self, event): action = QAction('remove product', self) action.setShortcut('Ctrl + R') action.setStatusTip('Removes a product from the selected shelf') - action.triggered.connect(lambda: self.delete_product(shelf, product_id)) + action.triggered.connect(lambda: self.delete_product(shelf, product_id)) self._menu.addAction(action) action = QAction('add product', self) action.setShortcut('Ctrl + A') action.setStatusTip('Adds a product to the selected shelf') - action.triggered.connect(lambda: self.add_product(shelf)) + action.triggered.connect(lambda: self.add_product(shelf)) self._menu.addAction(action) self._menu.popup(QPoint(event.x(),event.y())) @@ -829,17 +888,18 @@ def add_product(self, shelf): self._product_dialog.show() def delete_product(self, shelf, product_id): - shelf.delete_product(product_id) + shelf.delete_product(product_id) self._menu.hide() self.update() class TaskTable(QTableWidget): - def __init__(self): + def __init__(self): super(self.__class__, self).__init__() self._model = None + self.setWindowTitle('Tasks') self.setColumnCount(6) - self.setHorizontalHeaderLabels(['Task ID', 'Task Group', - 'Task Type', 'Assigned Robot', + self.setHorizontalHeaderLabels(['Task ID', 'Task Group', + 'Task Type', 'Assigned Robot', 'Checkpoint History', 'Open Checkpoints']) self.resizeColumnsToContents() self.resize(self.horizontalHeader().length() + 20, 200) @@ -912,16 +972,17 @@ def set_model(self, model): self._model.add_window(self) class ProgramEntry(object): - def __init__(self, program_name, short_program_name): + def __init__(self, program_name, short_program_name): self.program_name = program_name; self.short_program_name = short_program_name; self.text_field = None; class ParserWidget(QSplitter): - def __init__(self): + def __init__(self): super(self.__class__, self).__init__(Qt.Vertical) self._button_widget = QWidget(self) text_splitter = QSplitter(Qt.Horizontal, self) + self.setWindowTitle('Parser') self._program_tab = QTabWidget(text_splitter) self._program_list = [] self._atom_text = QTextEdit(text_splitter) @@ -944,12 +1005,12 @@ def __init__(self): self._reset_grounder_button.resize(140,30) self._reset_grounder_button.clicked.connect(self.reset_grounder) - self._reset_program_button = QPushButton('reset program', self._button_widget) + self._reset_program_button = QPushButton('reload program', self._button_widget) self._reset_program_button.move(420,5) self._reset_program_button.resize(140,30) self._reset_program_button.clicked.connect(self.reset_program) - self._reset_program_button = QPushButton('reset programs', self._button_widget) + self._reset_program_button = QPushButton('delete programs', self._button_widget) self._reset_program_button.move(560,5) self._reset_program_button.resize(140,30) self._reset_program_button.clicked.connect(self.reset_programs) @@ -964,6 +1025,8 @@ def __init__(self): self._parse_program_button.resize(140,30) self._parse_program_button.clicked.connect(self.delete_program) + self._button_widget.setFixedHeight(70) + self.move(0,0) self.resize(700,600) self.setSizes([70, 530]) @@ -984,13 +1047,13 @@ def changed(self): def reset_actions(self): if self._parser is None: return - self._parser.clear_model_actions() + self._parser.clear_model_actions() def reset_model(self): if self._parser is None: return self._parser.clear_model() - + def reset_grounder(self): if self._parser is None: return @@ -1001,6 +1064,7 @@ def reset_program(self): return index = self._program_tab.currentIndex() if index >= 0: + self.commit_programs() entry = self._program_list[index] self._parser.load(entry.program_name) @@ -1027,7 +1091,7 @@ def commit_programs(self): if not self._changed or self._parser is None: return for entry in self._program_list: - self._parser.set_program(entry.program_name, + self._parser.set_program(entry.program_name, entry.text_field.toPlainText()) def update(self): @@ -1037,6 +1101,7 @@ def update(self): add_entrys = []; delete_entrys = []; + current = self._program_tab.currentWidget() for entry in self._program_list: delete_entrys.append(entry) @@ -1078,3 +1143,7 @@ def update(self): self._atom_text.setText(self._parser.get_str_model()) self._edited = False + + index = self._program_tab.indexOf(current) + if index != -1: + self._program_tab.setCurrentIndex(index) diff --git a/visualizer/visualizer/model.py b/visualizer/visualizer/model.py index 4447695..54f6e9d 100644 --- a/visualizer/visualizer/model.py +++ b/visualizer/visualizer/model.py @@ -1,5 +1,6 @@ from visualizerItem import * from visualizerGraphicItem import * +from modelView import ModelView class Model(object): def __init__(self): @@ -24,6 +25,9 @@ def __init__(self): self._displayed_steps = -1 def clear(self): + for window in self._windows: + if isinstance(window, ModelView): + window.clear() self._items = {} self._graphic_items = {} self._new_items = {} @@ -35,7 +39,6 @@ def clear(self): self._highways = [] #pairs of x and y self._inits = [] #list of unhandled inits - self._num_steps = 0 self._current_step = 0 self._displayed_steps = -1 diff --git a/visualizer/visualizer/modelView.py b/visualizer/visualizer/modelView.py index e643c1e..8abc42a 100644 --- a/visualizer/visualizer/modelView.py +++ b/visualizer/visualizer/modelView.py @@ -245,9 +245,14 @@ def stop_timer(self): self._timer = None def speed_up_timer(self, speed_up): - self._timer_scale -= speed_up + self._timer_scale *= 1 - speed_up + if self._timer_scale <= 0.1: + self._timer_scale = 0.1 self.adjust_timer() + def get_timer_speedup(self): + return self._timer_scale + def is_timer_running(self): return self._timer is None @@ -318,6 +323,11 @@ def resize_to_fit(self): self._scale(zoom[0]/self._zoom[0], zoom[1]/self._zoom[1]) self._scene.setSceneRect(0, 0, self._line_hlength, self._line_vlength*1) + def clear(self): + for item in self._items_in_scene: + self._scene.removeItem(item) + self._items_in_scene = [] + def update(self): if self._model == None: return 0 @@ -338,9 +348,7 @@ def update(self): brush_disabled_node = QBrush(QColor(config.get('color', 'color_disabled_node'))) brush_highway = QBrush(QColor(config.get('color', 'color_highway'))) - for item in self._items_in_scene: - self._scene.removeItem(item) - self._items_in_scene = [] + self.clear() #draw vertival lines for i in range(0,self._model.get_grid_size()[1] + 1): diff --git a/visualizer/visualizer/network.py b/visualizer/visualizer/network.py index e25dc0b..015d346 100644 --- a/visualizer/visualizer/network.py +++ b/visualizer/visualizer/network.py @@ -41,7 +41,7 @@ def run_connection(self): self._timer.stop() self._timer = QTimer() self._timer.timeout.connect(self.receive) - self._timer.start(1000) + self._timer.start(1000) def connect(self, host = None, port = None): if self.is_connected() and host == self._host and port == self._port: @@ -50,8 +50,8 @@ def connect(self, host = None, port = None): self._host = host if port is not None: self._port = port - print 'Connect with '+ self._socket_name self.close() + print 'Try connection with '+ self._socket_name self._s = socket.socket() connected = False tryCount = 0 @@ -68,6 +68,7 @@ def connect(self, host = None, port = None): print 'Failed to connect with ' + self._socket_name + ' \nRetrying in 2 sek' time.sleep(2) tryCount += 1 + print 'Connect with '+ self._socket_name return 0 def send(self, msg): @@ -78,15 +79,18 @@ def send(self, msg): def _receive_data(self): breakLoop = False data = '' - ready = select.select([self._s], [], [], 0.1) - while (not breakLoop) and ready[0]: - new_data = self._s.recv(2048) - if not new_data.find('\n') == -1 or new_data == '': - breakLoop = True - data += new_data - if ready[0] and new_data == '': - self.close() - return None + try: + ready = select.select([self._s], [], [], 0.1) + while (not breakLoop) and ready[0]: + new_data = self._s.recv(2048) + if not new_data.find('\n') == -1 or new_data == '': + breakLoop = True + data += new_data + if ready[0] and new_data == '': + self.close() + return None + except socket.error as err: + print err return data def receive(self): @@ -141,6 +145,8 @@ def receive(self): if len(str_atom) != 0 and not (len(str_atom) == 1 and str_atom[0] == '\n'): if str_atom == '%$RESET': self._parser.clear_model_actions(True) + elif str_atom[0] == '\n': + pass else: self._parser.on_atom(clingo.parse_term(str_atom)) self._model.update_windows() @@ -149,6 +155,8 @@ def solve(self): if self._s == None or self._model == None: return -1 self._s.send('%$RESET.') self._model.set_editable(False) + self._model.clear_actions() + self._model.restart() for atom in self._model.to_init_str(): #send instance self._s.send(str(atom)) self._s.send('\n') diff --git a/visualizer/visualizer/parser.py b/visualizer/visualizer/parser.py index 5ce444a..7a97282 100644 --- a/visualizer/visualizer/parser.py +++ b/visualizer/visualizer/parser.py @@ -234,13 +234,13 @@ def parse_file(self, file_name, clear = False, clear_actions = False, clear_grou return -2 return 0 - def load_instance(self, file_name): + def load_instance(self, file_name, create_png = False): result = self.parse_file(file_name, clear = True) if result < 0: return result if (self._model_view is not None - and configuration.config.get('visualizer', 'create_pngs')): + and (configuration.config.get('visualizer', 'create_pngs') or create_png)): rect = self._model_view.sceneRect() position = self._model_view.mapFromScene(QPoint(rect.x(), rect.y())) diff --git a/visualizer/visualizer/visualizerGraphicItem.py b/visualizer/visualizer/visualizerGraphicItem.py index 52575c7..29985ac 100644 --- a/visualizer/visualizer/visualizerGraphicItem.py +++ b/visualizer/visualizer/visualizerGraphicItem.py @@ -35,7 +35,6 @@ def __init__(self, ID = 0, x = 0, y = 0): self._actions = [] self._colors = [QColor(0,0,0)] self._display_mode = 0 - self.setAcceptedMouseButtons(Qt.MouseButtons(1)) def set_starting_position(self, x, y): @@ -164,8 +163,9 @@ def paint(self, painter, option, widget): def mousePressEvent(self, event): if self._enable_drag: rect = self.get_rect() - self._dragged = (event.pos().x() - rect.x(), - event.pos().y() - rect.y()) + self._dragged = (event.scenePos().x(), + event.scenePos().y()) + event.accept() def mouseReleaseEvent(self, event): model_view = None @@ -176,20 +176,20 @@ def mouseReleaseEvent(self, event): model_view = view if model_view is None: return - node = model_view.scene_coordinates_to_node(event.pos().x(), - event.pos().y()) + node = model_view.scene_coordinates_to_node(event.scenePos().x(), + event.scenePos().y()) + self.setPos(0, 0) + if node is not None: self.edit_position_to(node[0], node[1]) model_view.update() + event.accept() def mouseMoveEvent(self, event): if self._dragged is None: return - rect = self.get_rect() - if rect is None: - return - rect.moveTo(event.pos().x() - self._dragged[0], event.pos().y() - self._dragged[1]) - self.set_rect(rect) + self.setPos(event.scenePos().x() - self._dragged[0], event.scenePos().y() - self._dragged[1]) + event.accept() class PickingStation(VisualizerGraphicItem): def __init__(self, ID = 0, x = 0, y = 0): From ba72e588f1e6fc83a8abceed2472ebf964a5a929 Mon Sep 17 00:00:00 2001 From: Philipp Obermeier Date: Thu, 29 Jun 2017 14:46:45 +0200 Subject: [PATCH 008/188] Visualizer: Fixed regression reg. python path --- visualizer/scripts/visualizer | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/visualizer/scripts/visualizer b/visualizer/scripts/visualizer index 54ecc84..fa03859 100755 --- a/visualizer/scripts/visualizer +++ b/visualizer/scripts/visualizer @@ -1,7 +1,7 @@ #! /usr/bin/env python import sys import os -sys.path.append(os.path.dirname(os.path.abspath(__file__)) + '/..') +sys.path.append(os.path.join(os.path.dirname(os.path.realpath(__file__)), '..')) import time import argparse from PyQt5.QtCore import * From 5e315fcf11a7ed8b28843f5a40b83ad87a988ed3 Mon Sep 17 00:00:00 2001 From: Philipp Obermeier Date: Mon, 26 Jun 2017 17:15:40 +0200 Subject: [PATCH 009/188] Checker Readme updated --- checker/README.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 checker/README.md diff --git a/checker/README.md b/checker/README.md new file mode 100644 index 0000000..3068106 --- /dev/null +++ b/checker/README.md @@ -0,0 +1,17 @@ +# Checker + +## About + +This is the checker of [ASPRILO](https://asprilo.github.io). + +## How To Use + +The checker is compartmentalized reflecting + * the problem domain + * the types of laws used for planning + * *executability* laws: possible actions based on preconditions + * *effect* laws: effects after an action execution and the state of the environment + * *static* laws: state constraints and transitions solely based on the current state of the environment + +## Example Invocations + From 2e8ac7748776628df73c069340e635c52710c0aa Mon Sep 17 00:00:00 2001 From: Philipp Obermeier Date: Tue, 27 Jun 2017 17:23:31 +0200 Subject: [PATCH 010/188] Instance conversion clarified - Also migrated from README.md to README.org, although not up-to-date --- checker/README.md | 17 ------ checker/README.org | 1 + checker/encodings/default/action-move.lp | 46 ++++++++++++++ .../default/action-pickup-putdown-deliver.lp | 61 +++++++++++++++++++ checker/encodings/default/actions.lp | 29 +++++++++ checker/encodings/default/checker.lp | 7 +++ checker/encodings/default/effects.lp | 18 ++++++ checker/encodings/default/instance.lp | 23 +++++++ checker/encodings/default/plan.lp | 8 +++ checker/encodings/default/show.lp | 9 +++ checker/encodings/default/static.lp | 24 ++++++++ checker/{TODO => scripts/checker.py} | 0 12 files changed, 226 insertions(+), 17 deletions(-) delete mode 100644 checker/README.md create mode 120000 checker/README.org create mode 100644 checker/encodings/default/action-move.lp create mode 100644 checker/encodings/default/action-pickup-putdown-deliver.lp create mode 100644 checker/encodings/default/actions.lp create mode 100644 checker/encodings/default/checker.lp create mode 100644 checker/encodings/default/effects.lp create mode 100644 checker/encodings/default/instance.lp create mode 100644 checker/encodings/default/plan.lp create mode 100644 checker/encodings/default/show.lp create mode 100644 checker/encodings/default/static.lp rename checker/{TODO => scripts/checker.py} (100%) diff --git a/checker/README.md b/checker/README.md deleted file mode 100644 index 3068106..0000000 --- a/checker/README.md +++ /dev/null @@ -1,17 +0,0 @@ -# Checker - -## About - -This is the checker of [ASPRILO](https://asprilo.github.io). - -## How To Use - -The checker is compartmentalized reflecting - * the problem domain - * the types of laws used for planning - * *executability* laws: possible actions based on preconditions - * *effect* laws: effects after an action execution and the state of the environment - * *static* laws: state constraints and transitions solely based on the current state of the environment - -## Example Invocations - diff --git a/checker/README.org b/checker/README.org new file mode 120000 index 0000000..81ba8cd --- /dev/null +++ b/checker/README.org @@ -0,0 +1 @@ +../docs/checker.org \ No newline at end of file diff --git a/checker/encodings/default/action-move.lp b/checker/encodings/default/action-move.lp new file mode 100644 index 0000000..6de0b55 --- /dev/null +++ b/checker/encodings/default/action-move.lp @@ -0,0 +1,46 @@ +% = ACTION: MOVEMENT =========================================================== + + +% - Domain --------------------------------------------------------------------- + +action(move(0,1)). +action(move(1,0)). +action(move(0,-1)). +action(move(-1,0)). + + +% - Preconditions - Verification ----------------------------------------------- + +% Target node not adjacent to robot +adjacent(R, DX, DY, T) :- at(robot(R), X, Y, T-1); node(X+DX, Y+DY); action(move(DX, DY)). +err(move(1), R, T) :- occurs(object(robot, R), action(move, (DX, DY)), T); not adjacent(R, DX, DY, T). + +% Target node occupied by other robot +err(move(2), R, T) :- occurs(object(robot, R), action(move, (DX, DY)), T); at(robot(R), X, Y, T-1); + { at(robot(_), X+DX, Y+DY, T) } > 1. + + +% - Effects -------------------------------------------------------------------- + +at(robot(R), X+DX, Y+DY, T) :- occurs(object(robot, R), action(move, (DX, DY)), T); + at(robot(R), X, Y, T-1); node(X+DX, Y+DY). +at(shelf(S), X, Y, T) :- at(robot(R), X, Y, T), carries(R, S, T-1). + +moves(robot(R), T) :- occurs(object(robot, R), action(move, _), T). % aux pred + +% - Inertia -------------------------------------------------------------------- + +at(robot(R), X, Y, T) :- at(robot(R), X, Y, T-1); not moves(robot(R), T); time(T). +at(shelf(R), X, Y, T) :- at(shelf(R), X, Y, T-1); not moves(robot(R), T); time(T); carries(R, S, T-1). + + +% - Static Laws - Verification ------------------------------------------------- + +% At most one robot (shelf) may occupy a node at the same time. +err(at(1), (X, Y), T) :- { at(robot(_), X, Y, T) } > 1; node(X, Y); time(T). +err(at(2), (X, Y), T) :- { at(shelf(_), X, Y, T) } > 1; node(X, Y); time(T). + +% Two adjacent robots must not swap places in one step, i.e, they would collide. +err(at(3), (R1, R2), T) :- at(robot(R1), X1, Y1, T), at(robot(R2), X2, Y2, T), + at(robot(R1), X2, Y2, T-1), at(robot(R2), X1, Y1 , T-1), + R1 RQ. + + +% - Effects -------------------------------------------------------------------- + + +carries(R, S, T) :- at(robot(R), X, Y, T-1); at(shelf(S), X, Y, T-1); + occurs(object(robot, R), action(pickup, ()), T). + +open(O, A, RQ-Q, T) :- open(O, A, RQ, T); occurs(object(robot, R), action(deliver, (O, A, Q)), T); RQ < Q. + +% - Inertia -------------------------------------------------------------------- + +carries(R, S, T) :- carries(R, S, T-1); not occurs(object(robot, R), action(putdown, ()), T). + +% - Static Laws - Verification ------------------------------------------------- + +% An order must be assigned to exactly one picking stations +err(assigned(1), O) :- { assigned(O, _) } > 1; order(O). diff --git a/checker/encodings/default/actions.lp b/checker/encodings/default/actions.lp new file mode 100644 index 0000000..7be1e42 --- /dev/null +++ b/checker/encodings/default/actions.lp @@ -0,0 +1,29 @@ +#include "./instance.lp". + +% = ACTIONS===================================================================== + + +% - Domain --------------------------------------------------------------------- + +action(move(0,1)). +action(move(1,0)). +action(move(0,-1)). +action(move(-1,0)). +action(pickup). +action(putdown). +action(deliver(O, A, Q)) :- init(object(order, O), value(line, (A, RQ))), + Q = 1..RQ . % RQ and Q are the requested + % and delivered quantity, resp. + +% -- Inertia ------------------------------------------------------------------- + +holds(F, T) :- holds(F, T-1), not abnormal(F, T). + + + + + + + + + diff --git a/checker/encodings/default/checker.lp b/checker/encodings/default/checker.lp new file mode 100644 index 0000000..3a19e2a --- /dev/null +++ b/checker/encodings/default/checker.lp @@ -0,0 +1,7 @@ +% Action Domain + +% Initial State + +% Inertia + +% Action diff --git a/checker/encodings/default/effects.lp b/checker/encodings/default/effects.lp new file mode 100644 index 0000000..62b7bf5 --- /dev/null +++ b/checker/encodings/default/effects.lp @@ -0,0 +1,18 @@ +% = ACTION EFFECTS ============================================================= +% +% This takes the plan facts, i.e., occurs/3 facts directly into account. + + +% - Movement ------------------------------------------------------------------- + +at(robot(R), X+DX, Y+DY, T) :- node(X+DX, Y+DY), at(robot(R), X, Y, T-1), + occurs(object(robot, R), value(move, (DX, DY)), T). +at(shelf(S), X, Y, T) :- at(robot(R), X, Y, T), holds(carries(R, S),T-1). +moved(robot(RID),t) :- occ(robot(RID),move(_,_),t), robot(RID). + + +% - Carrying ------------------------------------------------------------------- + +holds(carries(RID,SID),t) :- holds(at(robot(RID),node(X,Y)),t), + holds(at(shelf(SID),node(X,Y)),t), + occ(robot(RID),pickup,t). diff --git a/checker/encodings/default/instance.lp b/checker/encodings/default/instance.lp new file mode 100644 index 0000000..5f6ff9f --- /dev/null +++ b/checker/encodings/default/instance.lp @@ -0,0 +1,23 @@ +% = PROBLEM INSTANCE REPRESENTATION ================================================ + +% - Objects ------------------------------------------------------------------- + +node(X,Y) :- init(object(node, _), value(at, (X, Y))). +highway(X,Y) :- init(object(highway, _), value(at, (X, Y))). +robot(R) :- init(object(robot, R), _). +shelf(S) :- init(object(shelf, S), _). +station(P) :- init(object(pickingStation, P), _). +product(A) :- init(object(product, A), _). +order(O) :- init(object(order, O), _). + +% - Static Relations ----------------------------------------------------------- + +assigned(O, P) :- init(object(order, O), value(pickingStation, P)). +at(station(P), X, Y, 0) :- init(object(station, P), value(at, (X, Y))). + +% - Fluents --------------------------------------------------------------------- + +at(robot(R), X, Y, 0) :- init(object(robot, R), value(at, (X, Y))). +at(shelf(S), X, Y, 0) :- init(object(shelf, S), value(at, (X, Y))). +on(A, S, Q, 0) :- init(object(product, A), value(on, (S, Q))). % products on shelfs +open(O, A, Q, 0) :- init(object(order, O), value(line, (A, Q))). % unfullfilled order line diff --git a/checker/encodings/default/plan.lp b/checker/encodings/default/plan.lp new file mode 100644 index 0000000..f149e9e --- /dev/null +++ b/checker/encodings/default/plan.lp @@ -0,0 +1,8 @@ +% = PLAN REPRESENTAITON ======================================================== + +horizon(H) :- H = #max{0; T : occurs( _, _, T)} +time(1..H) :- horizon(H). + +#include "./action-move.lp". +#include "./action-pickup-putdown-deliver.lp". +#include "./goal.lp" diff --git a/checker/encodings/default/show.lp b/checker/encodings/default/show.lp new file mode 100644 index 0000000..a71fcd2 --- /dev/null +++ b/checker/encodings/default/show.lp @@ -0,0 +1,9 @@ +%% #show time/1. +%% #show action/1. +#show err/3. +%#show at/4. +%% #show moves/2. +%% #show node/2. +%% #show adjacent/4. +#show carries/3. + diff --git a/checker/encodings/default/static.lp b/checker/encodings/default/static.lp new file mode 100644 index 0000000..695ffe4 --- /dev/null +++ b/checker/encodings/default/static.lp @@ -0,0 +1,24 @@ +% STATIC LAWS ================================================================== + +% Only one robot (shel1f) at a node at the same time. +%% err(static(1),(X,Y)) :- node(X,Y), { at(robot(R), X, Y , T) : robot(R) } > 1. +%% err(static(2),(X,Y)) :- node(X,Y), { at(shelf(S), X, Y ,T) : shelf(S) } > 1. + +%% % A robot/shelf can only be at one node at a time. +%% :- robot(RID), 2{holds(at(robot(RID),node(X,Y)),t) : node(X,Y)}. +%% :- shelf(SID), 2{holds(at(shelf(SID),node(X,Y)),t) : node(X,Y)}. + +%% % Two robots can't swap places as they would crash. +%% :- holds(at(robot(RID1),node(X1,Y1)),t), holds(at(robot(RID2),node(X2,Y2)),t), +%% holds(at(robot(RID1),node(X2,Y2)),t-1), holds(at(robot(RID2),node(X1,Y1)),t-1), +%% RID1 Date: Mon, 3 Jul 2017 16:43:36 +0200 Subject: [PATCH 011/188] Added default, no quantities domain support - Switch to standard format --- checker/encodings/default/action-deliver.lp | 70 +++++++++++++++++++++ checker/encodings/default/action-move.lp | 56 ++++++++--------- checker/encodings/default/action-pickup.lp | 32 ++++++++++ checker/encodings/default/action-putdown.lp | 23 +++++++ checker/encodings/default/checker.lp | 29 +++++++-- checker/encodings/default/goal.lp | 4 ++ checker/encodings/default/init.lp | 16 +++++ checker/encodings/default/instance.lp | 23 ------- checker/encodings/default/plan.lp | 8 --- checker/encodings/default/static.lp | 68 +++++++++++++------- checker/encodings/dpq/action-deliver.lp | 40 ++++++++++++ checker/encodings/dpq/checker.lp | 28 +++++++++ docs/checker.org | 41 ++++++++++-- docs/visualizer.org | 2 +- 14 files changed, 346 insertions(+), 94 deletions(-) create mode 100644 checker/encodings/default/action-deliver.lp create mode 100644 checker/encodings/default/action-pickup.lp create mode 100644 checker/encodings/default/action-putdown.lp create mode 100644 checker/encodings/default/goal.lp create mode 100644 checker/encodings/default/init.lp delete mode 100644 checker/encodings/default/instance.lp delete mode 100644 checker/encodings/default/plan.lp create mode 100644 checker/encodings/dpq/action-deliver.lp create mode 100644 checker/encodings/dpq/checker.lp diff --git a/checker/encodings/default/action-deliver.lp b/checker/encodings/default/action-deliver.lp new file mode 100644 index 0000000..00715a2 --- /dev/null +++ b/checker/encodings/default/action-deliver.lp @@ -0,0 +1,70 @@ +% = ACTION: PICKUP, PUTDOWN, DELIVER =========================================== + + +% - Domain --------------------------------------------------------------------- + +action(deliver, (O, P, Q)) :- init(object(order, O), value(line, (P, RQ))), + Q = 1..RQ . % RQ and Q are the requested + % and delivered quantity, resp. + +% - Preconditions - Verification ----------------------------------------------- + +% Robot not at picking station +err(deliver_notAtPS, R, T) :- occurs(object(robot, R), action(deliver, (_, _, _)), T ); + holds(object( robot, R), value( at, (X, Y) ), T-1); + not holds(object( pickingStation, _), value( at, (X, Y) ), T-1). + +% Robot not carrying a shelf +err(deliver_noShelf, R, T) :- occurs(object(robot, R), action(deliver, (_, _, _)), T); + { holds( object(robot, R), value( carries, S ), T-1) : + holds( object(shelf, S), _ , T-1) } < 1. + + +% Robot delivers product that is not requested at picking stations +err(deliver_noOrder, R, T) :- occurs(object(robot, R ), action(deliver, (O, P, _)), T ); + holds( object( robot, R ), value( at, (X, Y) ), T-1); + holds( object( pickingStation, PS), value( at, (X, Y) ), T-1); + holds( object(order, O ), value( pickingStation, PS ), T-1); + not holds(object(order, O ), value( line, (P, _) ), T-1). + +% Robot delivers higher amount than requested +err(deliver_orderAmount, R, T) :- occurs(object(robot, R), action(deliver, (O, P, Q)), T); + holds( object(order, O), value( line, (P, RQ) ), T); + Q > RQ. + +% Robot delivers higher amount than available on shelf +err(deliver_shelfAmount, R, T) :- occurs(object(robot, R), action(deliver, (O, P, Q)), T); + holds( object(robot, R), value(carries, S ), T-1); + holds( object(product, P), value(on, (S, SQ) ) , T-1); + Q > SQ. + + +% Robot must deliver at least one unit +err(deliver_amount, R, T) :- occurs(object(robot, R), action(deliver, (_, _, 0)), T). + + +% - Book-Keeping: Effects ------------------------------------------------------- + +% Update order lines +holds(object(order,O), value(line, (P, RQ-Q)), T) :- occurs(object(robot, R), action(deliver, (O, A, Q)), T); + holds(object(order,O), value(line, (P, RQ)), T-1); + Q < RQ. +% Update product quantities on shelves + +holds(object(product, P), value(on, (S, SQ-Q)), T) :- occurs(object(robot, R), action(deliver, (_, P, Q)), T ); + holds( object(robot, R), value(carries, S ), T-1); + holds( object(product, P), value(on, (S, SQ) ), T-1); + Q < SQ. + + +% - Book-Keeping: Related Inertia Abnormals --------------------------------------- +% + +% Remove outdated order lines +ab(object(order, O), value(line, (P, RQ)), T) :- occurs(object(robot, R), action(deliver, (O, P, _)), T ); + holds(object(order,O), value( line, (P, RQ) ), T-1). + +% Remove outdated product quantites on shelves +ab(object(product, P), value(on, (S, SQ)), T) :- occurs(object(robot, R), action(deliver, (_, P, _)), T ); + holds( object(robot, R), value(carries, S ), T-1); + holds( object(product, P), value(on, (S, SQ) ), T-1). diff --git a/checker/encodings/default/action-move.lp b/checker/encodings/default/action-move.lp index 6de0b55..daffb97 100644 --- a/checker/encodings/default/action-move.lp +++ b/checker/encodings/default/action-move.lp @@ -1,46 +1,42 @@ -% = ACTION: MOVEMENT =========================================================== - +% = ACTION move ================================================================ % - Domain --------------------------------------------------------------------- -action(move(0,1)). -action(move(1,0)). -action(move(0,-1)). -action(move(-1,0)). - +action(move, (0,1)). +action(move, (1,0)). +action(move, (0,-1)). +action(move, (-1,0)). -% - Preconditions - Verification ----------------------------------------------- -% Target node not adjacent to robot -adjacent(R, DX, DY, T) :- at(robot(R), X, Y, T-1); node(X+DX, Y+DY); action(move(DX, DY)). -err(move(1), R, T) :- occurs(object(robot, R), action(move, (DX, DY)), T); not adjacent(R, DX, DY, T). +% - Checks: Preconditions ------------------------------------------------------ -% Target node occupied by other robot -err(move(2), R, T) :- occurs(object(robot, R), action(move, (DX, DY)), T); at(robot(R), X, Y, T-1); - { at(robot(_), X+DX, Y+DY, T) } > 1. +% Target node non-existent +err(move_node, R, T) :- occurs(object(robot, R), action(move, (DX, DY)), T ); + holds( object(robot, R), value(at, (X, Y)), T-1); + not holds( object(node, _), value(at, (X+DX, Y+DY)), T ). +% Movement domain violated +err(move_domain, R, T) :- occurs(object(robot, R), action(move, (DX, DY)), T ); + holds( object(robot, R), value(at, (X, Y)), T-1); + not action(move, (DX, DY)). -% - Effects -------------------------------------------------------------------- -at(robot(R), X+DX, Y+DY, T) :- occurs(object(robot, R), action(move, (DX, DY)), T); - at(robot(R), X, Y, T-1); node(X+DX, Y+DY). -at(shelf(S), X, Y, T) :- at(robot(R), X, Y, T), carries(R, S, T-1). -moves(robot(R), T) :- occurs(object(robot, R), action(move, _), T). % aux pred +%adjacent(R, DX, DY, T) :- holds( object(node, _), value(at, (X+DX, Y+DY)), T ).at(robot(R), X, Y, T-1); node(X+DX, Y+DY); action(move(DX, DY)). -% - Inertia -------------------------------------------------------------------- +% - Book-Keeping: Effects -------------------------------------------------------------------- -at(robot(R), X, Y, T) :- at(robot(R), X, Y, T-1); not moves(robot(R), T); time(T). -at(shelf(R), X, Y, T) :- at(shelf(R), X, Y, T-1); not moves(robot(R), T); time(T); carries(R, S, T-1). +holds(object(robot, R), value(at, (X+DX, Y+DY)), T) :- occurs(object(robot, R), action(move, (DX, DY)), T ); + holds( object(robot, R), value(at, (X, Y)), T-1). +holds(object(shelf, S), value(at, (X, Y )), T) :- holds( object(robot, R), value(at, (X, Y)), T ); + holds( object(robot, R), value(carries, (R, S)), T-1). -% - Static Laws - Verification ------------------------------------------------- -% At most one robot (shelf) may occupy a node at the same time. -err(at(1), (X, Y), T) :- { at(robot(_), X, Y, T) } > 1; node(X, Y); time(T). -err(at(2), (X, Y), T) :- { at(shelf(_), X, Y, T) } > 1; node(X, Y); time(T). +% - Book-Keeping: Related Inertia Abnormals --------------------------------------- -% Two adjacent robots must not swap places in one step, i.e, they would collide. -err(at(3), (R1, R2), T) :- at(robot(R1), X1, Y1, T), at(robot(R2), X2, Y2, T), - at(robot(R1), X2, Y2, T-1), at(robot(R2), X1, Y1 , T-1), - R1 1. -%% err(static(2),(X,Y)) :- node(X,Y), { at(shelf(S), X, Y ,T) : shelf(S) } > 1. - -%% % A robot/shelf can only be at one node at a time. -%% :- robot(RID), 2{holds(at(robot(RID),node(X,Y)),t) : node(X,Y)}. -%% :- shelf(SID), 2{holds(at(shelf(SID),node(X,Y)),t) : node(X,Y)}. - -%% % Two robots can't swap places as they would crash. -%% :- holds(at(robot(RID1),node(X1,Y1)),t), holds(at(robot(RID2),node(X2,Y2)),t), -%% holds(at(robot(RID1),node(X2,Y2)),t-1), holds(at(robot(RID2),node(X1,Y1)),t-1), -%% RID1 1; + holds(object(node, _), value(at, (X, Y)), T); + init( object(OT, _), _); + time(T). + + +% Two adjacent objects of the same type (robots, shelves) must not swap places in one step, i.e, +% they would collide. +err(static_collSwap, (OT, R1, R2), T) :- holds(object(OT, R1), value(at, (X1, Y1)), T); + holds(object(OT, R2), value(at, (X2, Y2)), T); + holds(object(OT, R1), value(at, (X2, Y2)), T-1); + holds(object(OT, R1), value(at, (X1, Y1)), T-1); + R1 1; + init(object(OT, O), _); + time(T). + +% An object can only do one action at a time. +err(static_multActions, (OT, O), T ) :- { occurs(object(OT, O), _, T) } > 1; + init(object(OT, O), _); + time(T). + +% A robot must never place a shelves on a highway node. +err(static_highwayPutdown, (R, X, Y), T) :- holds( object(highway, _), value(at, (X, Y)), T); + holds( object(robot, R), value(at, (X, Y)), T); + occurs(object(robot, R), action(putdown, ()), T); + time(T). + +% An order must be assigned to exactly one picking stations +err(static_assigned, O) :- { holds(object(order, O), value(pickingStation, _), T) } > 1; + holds(object(order, O), _, T); + time(T). +err(static_assigned, O) :- { holds(object(order, O), value(pickingStation, _), T) } < 1; + holds(object(order, O), _, T); + time(T). diff --git a/checker/encodings/dpq/action-deliver.lp b/checker/encodings/dpq/action-deliver.lp new file mode 100644 index 0000000..ce54100 --- /dev/null +++ b/checker/encodings/dpq/action-deliver.lp @@ -0,0 +1,40 @@ +% = ACTION: PICKUP, PUTDOWN, DELIVER =========================================== + + +% - Domain --------------------------------------------------------------------- + +action(deliver, (O, P, Q)) :- init(object(order, O), value(line, (P, RQ))), + Q = 1..RQ . % RQ and Q are the requested + % and delivered quantity, resp. + +% - Preconditions - Verification ----------------------------------------------- + +% Robot not at picking station +err(deliver_notAtPS, R, T) :- occurs(object(robot, R), action(deliver, (_, _, _)), T ); + holds(object( robot, R), value( at, (X, Y) ), T-1); + not holds(object( pickingStation, _), value( at, (X, Y) ), T-1). + +% Robot not carrying a shelf +err(deliver_noShelf, R, T) :- occurs(object(robot, R), action(deliver, (_, _, _)), T); + { holds( object(robot, R), value( carries, S ), T-1) : + holds( object(shelf, S), _ , T-1) } < 1. + + +% Robot delivers product that is not requested at picking stations +err(deliver_noOrder, R, T) :- occurs(object(robot, R ), action(deliver, (O, P, _)), T ); + holds( object( robot, R ), value( at, (X, Y) ), T-1); + holds( object( pickingStation, PS), value( at, (X, Y) ), T-1); + holds( object(order, O ), value( pickingStation, PS ), T-1); + not holds(object(order, O ), value( line, (P, _) ), T-1). + +% Robot delivers higher amount than requested +err(deliver_orderAmount, R, T) :- occurs(object(robot, R), action(deliver, (O, P, Q)), T); + holds( object(order, O), value( line, (P, RQ) ), T); + Q > RQ. + + +% - Book-Keeping: Related Inertia Abnormals --------------------------------------- +% + +% Remove outdated order lines +ab(object(order, O), value(line, (P, RQ)), T) :- occurs(object(robot, R), action(deliver, (O, P) ), T ); diff --git a/checker/encodings/dpq/checker.lp b/checker/encodings/dpq/checker.lp new file mode 100644 index 0000000..77048dc --- /dev/null +++ b/checker/encodings/dpq/checker.lp @@ -0,0 +1,28 @@ +% = CHECKER ENCODINGS FOR THE DEFAULT PROBLEM DOMAIN =========================== + +% - Initial Setup -------------------------------------------------------------- +% +% Sets up inital state, horizon and general inertia axiom + +#include "../default/init.lp". + + +% - Checks and Book-Keeping Entailments Per Action ----------------------------- +% +% Per each action, conduct +% - checks for preconditions +% - "book-keeping" entailments for effects and related inertial abnormalities + +#include "../default/action-move.lp". +#include "../default/action-pickup.lp". +#include "../default/action-putdown.lp". +#include "action-deliver.lp". + + +% - Checks for Static Law Violations ------------------------------------------- + +#include "../default/static.lp". + +% - Goal condition ------------------------------------------------------------- + +#include "../default/goal.lp". diff --git a/docs/checker.org b/docs/checker.org index ce887c2..1c66790 100644 --- a/docs/checker.org +++ b/docs/checker.org @@ -1,12 +1,45 @@ -#+TITLE: ASPRILO Solution Checker +#+TITLE: ASPRILO Checker #+AUTHOR: Philipp Obermeier #+INCLUDE: "./conf.org" * About + :PROPERTIES: + :CUSTOM_ID: checker_about + :END: - This is the user manual of the solution checker of ASPRILO. + This is the user manual of the solution checker of [[file:index.org][ASPRILO]]. +* Encoding Architecture -* Invocation + The encoding for verification is compartmentalized into several categories reflecting - TODO + 1. the problem domain + + - stored in =./checker/encodings//= .e.g. + =./checker/encodings/default/= for the default domain + + 2. the types of laws used for planning, that is, + + 1. /action executability/: possible actions based on preconditions + + - stored in =./checker/encodings//actions= + + 2. /action effects/: effects after an action execution and the state + of the environment + + - stored in =./checker/encodings//effects= + + 3. /static laws/: state constraints and transitions solely based on + the current state of the environment (fluents) + + - stored in=./checker/encodings//states= + +* How To Use + :PROPERTIES: + :CUSTOM_ID: checker_how-to-use + :END: + +* Example Invocations + :PROPERTIES: + :CUSTOM_ID: checker_example-invocations + :END: diff --git a/docs/visualizer.org b/docs/visualizer.org index 67c34d1..50ac209 100644 --- a/docs/visualizer.org +++ b/docs/visualizer.org @@ -4,7 +4,7 @@ * About - This is the user manual of the visualizer of [[file:index.org][ASPRILO]]. + This is the user manual of the instance and plan visualizer of [[file:index.org][ASPRILO]]. * Invocation From 474762d8171400017bbd3f85e0290ca9ca458665 Mon Sep 17 00:00:00 2001 From: Philipp Obermeier Date: Fri, 7 Jul 2017 16:20:24 +0200 Subject: [PATCH 012/188] Adjusted signature of error predicate - Deletion of redundant encodings - Minor cleanups - Minor fixes --- checker/encodings/default/action-deliver.lp | 57 +++++++++-------- checker/encodings/default/action-move.lp | 12 ++-- .../default/action-pickup-putdown-deliver.lp | 61 ------------------- checker/encodings/default/action-pickup.lp | 11 ++-- checker/encodings/default/action-putdown.lp | 5 +- checker/encodings/default/actions.lp | 29 --------- checker/encodings/default/effects.lp | 18 ------ checker/encodings/default/goal.lp | 4 +- checker/encodings/default/static.lp | 52 ++++++++-------- checker/encodings/dpq/action-deliver.lp | 31 +++++----- 10 files changed, 87 insertions(+), 193 deletions(-) delete mode 100644 checker/encodings/default/action-pickup-putdown-deliver.lp delete mode 100644 checker/encodings/default/actions.lp delete mode 100644 checker/encodings/default/effects.lp diff --git a/checker/encodings/default/action-deliver.lp b/checker/encodings/default/action-deliver.lp index 00715a2..3d87e87 100644 --- a/checker/encodings/default/action-deliver.lp +++ b/checker/encodings/default/action-deliver.lp @@ -7,48 +7,47 @@ action(deliver, (O, P, Q)) :- init(object(order, O), value(line, (P, RQ))), Q = 1..RQ . % RQ and Q are the requested % and delivered quantity, resp. + % - Preconditions - Verification ----------------------------------------------- % Robot not at picking station -err(deliver_notAtPS, R, T) :- occurs(object(robot, R), action(deliver, (_, _, _)), T ); - holds(object( robot, R), value( at, (X, Y) ), T-1); - not holds(object( pickingStation, _), value( at, (X, Y) ), T-1). +err(deliver, notAtPS, (R, T)) :- occurs(object(robot, R), action(deliver, (_, _, _)), T ); + holds(object( robot, R), value( at, (X, Y) ), T-1); + not holds(object( pickingStation, _), value( at, (X, Y) ), T-1). % Robot not carrying a shelf -err(deliver_noShelf, R, T) :- occurs(object(robot, R), action(deliver, (_, _, _)), T); - { holds( object(robot, R), value( carries, S ), T-1) : - holds( object(shelf, S), _ , T-1) } < 1. - +err(deliver, noShelf, (R, T)) :- occurs(object(robot, R), action(deliver, (_, _, _)), T); + { holds( object(robot, R), value( carries, S ), T-1) : + holds( object(shelf, S), _ , T-1) } < 1. % Robot delivers product that is not requested at picking stations -err(deliver_noOrder, R, T) :- occurs(object(robot, R ), action(deliver, (O, P, _)), T ); - holds( object( robot, R ), value( at, (X, Y) ), T-1); - holds( object( pickingStation, PS), value( at, (X, Y) ), T-1); - holds( object(order, O ), value( pickingStation, PS ), T-1); - not holds(object(order, O ), value( line, (P, _) ), T-1). +err(deliver, noOrder, (R, T)) :- occurs(object(robot, R ), action(deliver, (O, P, _)), T ); + holds( object( robot, R ), value( at, (X, Y) ), T-1); + holds( object( pickingStation, PS), value( at, (X, Y) ), T-1); + holds( object(order, O ), value( pickingStation, PS ), T-1); + not holds(object(order, O ), value( line, (P, _) ), T-1). % Robot delivers higher amount than requested -err(deliver_orderAmount, R, T) :- occurs(object(robot, R), action(deliver, (O, P, Q)), T); - holds( object(order, O), value( line, (P, RQ) ), T); - Q > RQ. +err(deliver, orderAmount, (R, T)) :- occurs(object(robot, R), action(deliver, (O, P, Q)), T); + holds( object(order, O), value( line, (P, RQ) ), T); + Q > RQ. % Robot delivers higher amount than available on shelf -err(deliver_shelfAmount, R, T) :- occurs(object(robot, R), action(deliver, (O, P, Q)), T); - holds( object(robot, R), value(carries, S ), T-1); - holds( object(product, P), value(on, (S, SQ) ) , T-1); - Q > SQ. - +err(deliver, shelfAmount, (R, T)) :- occurs(object(robot, R), action(deliver, (O, P, Q)), T); + holds( object(robot, R), value(carries, S ), T-1); + holds( object(product, P), value(on, (S, SQ) ) , T-1); + Q > SQ. % Robot must deliver at least one unit -err(deliver_amount, R, T) :- occurs(object(robot, R), action(deliver, (_, _, 0)), T). +err(deliver, zeroAmount, (R, T)) :- occurs(object(robot, R), action(deliver, (_, _, 0)), T). % - Book-Keeping: Effects ------------------------------------------------------- % Update order lines -holds(object(order,O), value(line, (P, RQ-Q)), T) :- occurs(object(robot, R), action(deliver, (O, A, Q)), T); +holds(object(order, O), value(line, (P, RQ-Q)), T) :- occurs(object(robot, R), action(deliver, (O, P, Q)), T); holds(object(order,O), value(line, (P, RQ)), T-1); - Q < RQ. + Q < RQ. % Update product quantities on shelves holds(object(product, P), value(on, (S, SQ-Q)), T) :- occurs(object(robot, R), action(deliver, (_, P, Q)), T ); @@ -61,10 +60,10 @@ holds(object(product, P), value(on, (S, SQ-Q)), T) :- occurs(object(robot, R), % % Remove outdated order lines -ab(object(order, O), value(line, (P, RQ)), T) :- occurs(object(robot, R), action(deliver, (O, P, _)), T ); - holds(object(order,O), value( line, (P, RQ) ), T-1). - +ab(object(order, O), value(line, (P, RQ)), T) :- occurs(object(robot, R), action(deliver, (O, P, _)), T ); + holds( object(order, O), value( line, (P, RQ) ), T-1). + % Remove outdated product quantites on shelves -ab(object(product, P), value(on, (S, SQ)), T) :- occurs(object(robot, R), action(deliver, (_, P, _)), T ); - holds( object(robot, R), value(carries, S ), T-1); - holds( object(product, P), value(on, (S, SQ) ), T-1). +ab(object(product, P), value(on, (S, SQ)), T) :- occurs(object(robot, R), action(deliver, (_, P, _)), T ); + holds( object(robot, R), value(carries, S ), T-1); + holds( object(product, P), value(on, (S, SQ) ), T-1). diff --git a/checker/encodings/default/action-move.lp b/checker/encodings/default/action-move.lp index daffb97..049875e 100644 --- a/checker/encodings/default/action-move.lp +++ b/checker/encodings/default/action-move.lp @@ -11,14 +11,14 @@ action(move, (-1,0)). % - Checks: Preconditions ------------------------------------------------------ % Target node non-existent -err(move_node, R, T) :- occurs(object(robot, R), action(move, (DX, DY)), T ); - holds( object(robot, R), value(at, (X, Y)), T-1); - not holds( object(node, _), value(at, (X+DX, Y+DY)), T ). +err(move, node, (R, T)) :- occurs(object(robot, R), action(move, (DX, DY)), T ); + holds( object(robot, R), value(at, (X, Y)), T-1); + not holds( object(node, _), value(at, (X+DX, Y+DY)), T ). % Movement domain violated -err(move_domain, R, T) :- occurs(object(robot, R), action(move, (DX, DY)), T ); - holds( object(robot, R), value(at, (X, Y)), T-1); - not action(move, (DX, DY)). +err(move, domain, (R, T)) :- occurs(object(robot, R), action(move, (DX, DY)), T ); + holds( object(robot, R), value(at, (X, Y)), T-1); + not action(move, (DX, DY)). diff --git a/checker/encodings/default/action-pickup-putdown-deliver.lp b/checker/encodings/default/action-pickup-putdown-deliver.lp deleted file mode 100644 index 8d6ce16..0000000 --- a/checker/encodings/default/action-pickup-putdown-deliver.lp +++ /dev/null @@ -1,61 +0,0 @@ -% = ACTION: PICKUP, PUTDOWN, DELIVER =========================================== - - -% - Domain --------------------------------------------------------------------- - -action(pickup). -action(putdown). -action(deliver(O, A, Q)) :- init(object(order, O), value(line, (A, RQ))), - Q = 1..RQ . % RQ and Q are the requested - % and delivered quantity, resp. - -% - Preconditions - Verification ----------------------------------------------- - -% Pickup: no shelf to pickup at location -err(pickup(1), R, T) :- at(robot(R), X, Y, T-1); not at(shelf(_), X, Y, T-1); - occurs(object(robot, R), action(pickup, ()), T). - -% Pickup: robot already carries a shelf -err(pickup(2), R, T) :- carries(R, _, T-1); occurs(object(robot, R), action(pickup, ()), T). - -% Putdown: robot does not carry a shelf -err(putdown(1), R, T) :- not carries(R, _, T-1); occurs(object(robot, R), action(putdown, ()), T). - -% Putdown: robot tries to putdown shelf on highway node -err(putdown(2), R, T) :- at(robot(R), X, Y, T-1); highway(X, Y); occurs(object(robot, R), action(putdown, ()), T). - - -% Deliver: robot not at picking station -err(deliver(1), R, T) :- at(robot(R), X, Y, T-1); not at(station(_), X, Y, T-1); - occurs(object(robot, R), action(deliver, (_, _, _)), T). - -% Deliver: robot not carrying a shelf -err(deliver(2), R, T) :- not carries(R, _, T); occurs(object(robot, R), action(deliver, (_, _, _)), T). - - -% Deliver: robot delivers product that is not requested at picking stations -err(deliver(3), R, T) :- at(robot(R), X, Y, T-1); at(station(P), X, Y, T-1); - not open(_, A, _, T-1); assigned(O, P); - occurs(object(robot, R), action(deliver, (O, A, _)), T). - -% Deliver: robot delivers higher amount than requested -err(deliver(4), R, T) :- at(robot(R), X, Y, T-1); open(_, A, RQ, T-1); - occurs(object(robot, R), action(deliver, (P, A, Q)), T); Q > RQ. - - -% - Effects -------------------------------------------------------------------- - - -carries(R, S, T) :- at(robot(R), X, Y, T-1); at(shelf(S), X, Y, T-1); - occurs(object(robot, R), action(pickup, ()), T). - -open(O, A, RQ-Q, T) :- open(O, A, RQ, T); occurs(object(robot, R), action(deliver, (O, A, Q)), T); RQ < Q. - -% - Inertia -------------------------------------------------------------------- - -carries(R, S, T) :- carries(R, S, T-1); not occurs(object(robot, R), action(putdown, ()), T). - -% - Static Laws - Verification ------------------------------------------------- - -% An order must be assigned to exactly one picking stations -err(assigned(1), O) :- { assigned(O, _) } > 1; order(O). diff --git a/checker/encodings/default/action-pickup.lp b/checker/encodings/default/action-pickup.lp index a4a06a8..6697c29 100644 --- a/checker/encodings/default/action-pickup.lp +++ b/checker/encodings/default/action-pickup.lp @@ -5,19 +5,20 @@ action(pickup, ()). + % - Preconditions - Verification ----------------------------------------------- % No shelf to pickup at location -err(pickup_noShelf, R, T) :- occurs(object(robot, R), action(pickup, ()), T); - holds( object(robot, R), value(at, (X, Y)), T-1); - not holds( object(shelf, _), value(at, (X, Y)), T-1). +err(pickup, noShelf, (R, T)) :- occurs(object(robot, R), action(pickup, ()), T); + holds( object(robot, R), value(at, (X, Y)), T-1); + not holds( object(shelf, _), value(at, (X, Y)), T-1). % Robot already carries a shelf -err(pickup_carries, R, T) :- occurs(object(robot, R), action(pickup, ()), T); - holds(object(R, _), value(carries, _), T-1). +err(pickup, carries, (R, T)) :- occurs(object(robot, R), action(pickup, ()), T); + holds(object(R, _), value(carries, _), T-1). % - Book-Keeping: Effects -------------------------------------------------------------------- diff --git a/checker/encodings/default/action-putdown.lp b/checker/encodings/default/action-putdown.lp index 57b87f0..b3deb82 100644 --- a/checker/encodings/default/action-putdown.lp +++ b/checker/encodings/default/action-putdown.lp @@ -5,11 +5,12 @@ action(putdown, ()). + % - Preconditions - Verification ----------------------------------------------- % Robot does not carry a shelf -err(putdown_noShelf, R, T) :- occurs(object(robot, R), action(putdown, ()), T ); - not holds( object(robot, R), value(carries, _), T-1). +err(putdown, noShelf, (R, T)) :- occurs(object(robot, R), action(putdown, ()), T ); + not holds( object(robot, R), value(carries, _), T-1). % - Book-Keeping: Effects -------------------------------------------------------------------- diff --git a/checker/encodings/default/actions.lp b/checker/encodings/default/actions.lp deleted file mode 100644 index 7be1e42..0000000 --- a/checker/encodings/default/actions.lp +++ /dev/null @@ -1,29 +0,0 @@ -#include "./instance.lp". - -% = ACTIONS===================================================================== - - -% - Domain --------------------------------------------------------------------- - -action(move(0,1)). -action(move(1,0)). -action(move(0,-1)). -action(move(-1,0)). -action(pickup). -action(putdown). -action(deliver(O, A, Q)) :- init(object(order, O), value(line, (A, RQ))), - Q = 1..RQ . % RQ and Q are the requested - % and delivered quantity, resp. - -% -- Inertia ------------------------------------------------------------------- - -holds(F, T) :- holds(F, T-1), not abnormal(F, T). - - - - - - - - - diff --git a/checker/encodings/default/effects.lp b/checker/encodings/default/effects.lp deleted file mode 100644 index 62b7bf5..0000000 --- a/checker/encodings/default/effects.lp +++ /dev/null @@ -1,18 +0,0 @@ -% = ACTION EFFECTS ============================================================= -% -% This takes the plan facts, i.e., occurs/3 facts directly into account. - - -% - Movement ------------------------------------------------------------------- - -at(robot(R), X+DX, Y+DY, T) :- node(X+DX, Y+DY), at(robot(R), X, Y, T-1), - occurs(object(robot, R), value(move, (DX, DY)), T). -at(shelf(S), X, Y, T) :- at(robot(R), X, Y, T), holds(carries(R, S),T-1). -moved(robot(RID),t) :- occ(robot(RID),move(_,_),t), robot(RID). - - -% - Carrying ------------------------------------------------------------------- - -holds(carries(RID,SID),t) :- holds(at(robot(RID),node(X,Y)),t), - holds(at(shelf(SID),node(X,Y)),t), - occ(robot(RID),pickup,t). diff --git a/checker/encodings/default/goal.lp b/checker/encodings/default/goal.lp index 755f7a7..cb2edcc 100644 --- a/checker/encodings/default/goal.lp +++ b/checker/encodings/default/goal.lp @@ -1,4 +1,4 @@ % = GOAL CONDITION ============================================================= -err(openOrder, (O, P, Q), H) :- holds(object(order, O), value(line, (P, Q)), H); - horizon(H). +err(goal, unfilledOrder, (O, P, Q, H)) :- holds(object(order, O), value(line, (P, Q)), H); + horizon(H). diff --git a/checker/encodings/default/static.lp b/checker/encodings/default/static.lp index 967f68f..caed80a 100644 --- a/checker/encodings/default/static.lp +++ b/checker/encodings/default/static.lp @@ -4,41 +4,41 @@ % At most one object of the same type (robot. shelf, picking station, etc.) may occupy a node at % the same time, otherwise collision. -err(static_collNode, (OT, X, Y), T) :- { holds(object(OT, _), value(at, (X, Y)), T) } > 1; - holds(object(node, _), value(at, (X, Y)), T); - init( object(OT, _), _); - time(T). +err(static, collNode, (OT, X, Y, T)) :- { holds(object(OT, _), value(at, (X, Y)), T) } > 1; + holds(object(node, _), value(at, (X, Y)), T); + init( object(OT, _), _); + time(T). % Two adjacent objects of the same type (robots, shelves) must not swap places in one step, i.e, % they would collide. -err(static_collSwap, (OT, R1, R2), T) :- holds(object(OT, R1), value(at, (X1, Y1)), T); - holds(object(OT, R2), value(at, (X2, Y2)), T); - holds(object(OT, R1), value(at, (X2, Y2)), T-1); - holds(object(OT, R1), value(at, (X1, Y1)), T-1); - R1 1; - init(object(OT, O), _); - time(T). +err(static, twoPos, (OT,O, T)) :- { holds(object(OT, O), value(at, (X, Y)), T) : + holds(object(node, _), value(at, (X, Y)), T) } > 1; + init(object(OT, O), _); + time(T). % An object can only do one action at a time. -err(static_multActions, (OT, O), T ) :- { occurs(object(OT, O), _, T) } > 1; - init(object(OT, O), _); - time(T). +err(static, multActions, (OT, O, T)) :- { occurs(object(OT, O), _, T) } > 1; + init(object(OT, O), _); + time(T). % A robot must never place a shelves on a highway node. -err(static_highwayPutdown, (R, X, Y), T) :- holds( object(highway, _), value(at, (X, Y)), T); - holds( object(robot, R), value(at, (X, Y)), T); - occurs(object(robot, R), action(putdown, ()), T); - time(T). +err(static, highwayPutdown, (R, X, Y, T)) :- holds( object(highway, _), value(at, (X, Y)), T); + holds( object(robot, R), value(at, (X, Y)), T); + occurs(object(robot, R), action(putdown, ()), T); + time(T). % An order must be assigned to exactly one picking stations -err(static_assigned, O) :- { holds(object(order, O), value(pickingStation, _), T) } > 1; - holds(object(order, O), _, T); - time(T). -err(static_assigned, O) :- { holds(object(order, O), value(pickingStation, _), T) } < 1; - holds(object(order, O), _, T); - time(T). +err(static, assigned, O) :- { holds(object(order, O), value(pickingStation, _), T) } > 1; + holds(object(order, O), _, T); + time(T). +err(static, assigned, O) :- { holds(object(order, O), value(pickingStation, _), T) } < 1; + holds(object(order, O), _, T); + time(T). diff --git a/checker/encodings/dpq/action-deliver.lp b/checker/encodings/dpq/action-deliver.lp index ce54100..5010951 100644 --- a/checker/encodings/dpq/action-deliver.lp +++ b/checker/encodings/dpq/action-deliver.lp @@ -10,31 +10,32 @@ action(deliver, (O, P, Q)) :- init(object(order, O), value(line, (P, RQ))), % - Preconditions - Verification ----------------------------------------------- % Robot not at picking station -err(deliver_notAtPS, R, T) :- occurs(object(robot, R), action(deliver, (_, _, _)), T ); - holds(object( robot, R), value( at, (X, Y) ), T-1); - not holds(object( pickingStation, _), value( at, (X, Y) ), T-1). +err(deliver, notAtPS, (R, T)) :- occurs(object(robot, R), action(deliver, (_, _, _)), T ); + holds(object( robot, R), value( at, (X, Y) ), T-1); + not holds(object( pickingStation, _), value( at, (X, Y) ), T-1). % Robot not carrying a shelf -err(deliver_noShelf, R, T) :- occurs(object(robot, R), action(deliver, (_, _, _)), T); - { holds( object(robot, R), value( carries, S ), T-1) : - holds( object(shelf, S), _ , T-1) } < 1. +err(delive, noShelf, (R, T)) :- occurs(object(robot, R), action(deliver, (_, _, _)), T); + { holds( object(robot, R), value( carries, S ), T-1) : + holds( object(shelf, S), _ , T-1) } < 1. % Robot delivers product that is not requested at picking stations -err(deliver_noOrder, R, T) :- occurs(object(robot, R ), action(deliver, (O, P, _)), T ); - holds( object( robot, R ), value( at, (X, Y) ), T-1); - holds( object( pickingStation, PS), value( at, (X, Y) ), T-1); - holds( object(order, O ), value( pickingStation, PS ), T-1); - not holds(object(order, O ), value( line, (P, _) ), T-1). +err(deliver, noOrder, (R, T)) :- occurs(object(robot, R ), action(deliver, (O, P, _)), T ); + holds( object( robot, R ), value( at, (X, Y) ), T-1); + holds( object( pickingStation, PS), value( at, (X, Y) ), T-1); + holds( object(order, O ), value( pickingStation, PS ), T-1); + not holds(object(order, O ), value( line, (P, _) ), T-1). % Robot delivers higher amount than requested -err(deliver_orderAmount, R, T) :- occurs(object(robot, R), action(deliver, (O, P, Q)), T); - holds( object(order, O), value( line, (P, RQ) ), T); - Q > RQ. +err(deliver, orderAmount, (R, T)) :- occurs(object(robot, R), action(deliver, (O, P, Q)), T); + holds( object(order, O), value( line, (P, RQ) ), T); + Q > RQ. % - Book-Keeping: Related Inertia Abnormals --------------------------------------- % % Remove outdated order lines -ab(object(order, O), value(line, (P, RQ)), T) :- occurs(object(robot, R), action(deliver, (O, P) ), T ); +ab(object(order, O), value(line, (P, RQ)), T) :- occurs(object(robot, R), action(deliver, (O, P )), T ); + holds(object(order,O), value( line, (P, RQ)), T-1). From e5f689202411778b0e73852da8f73c89d68555f7 Mon Sep 17 00:00:00 2001 From: Philipp Obermeier Date: Tue, 11 Jul 2017 20:55:55 +0200 Subject: [PATCH 013/188] Checker Readme revised --- docs/checker.org | 99 +++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 81 insertions(+), 18 deletions(-) diff --git a/docs/checker.org b/docs/checker.org index 1c66790..05a9315 100644 --- a/docs/checker.org +++ b/docs/checker.org @@ -9,37 +9,100 @@ This is the user manual of the solution checker of [[file:index.org][ASPRILO]]. -* Encoding Architecture - The encoding for verification is compartmentalized into several categories reflecting +* Encoding Structure - 1. the problem domain + The checker's encoding is compartmentalized into several parts with respect to - - stored in =./checker/encodings//= .e.g. - =./checker/encodings/default/= for the default domain + 1. the problem domain, i.e., all encodings related to a domain =DOMAIN= are stored in a separate + directory =./checker/encodings/DOMAIN/=, .e.g. =./checker/encodings/default/= for the [[file:~/logistics/ASPRILO/public/asprilo/docs/specification.org::#cid:b0f981f8-3202-42c0-a46e-aa6f1a52629b][default + domain]] - 2. the types of laws used for planning, that is, - 1. /action executability/: possible actions based on preconditions + 2. the initial environmental state and the general law of inertia stored in + =./checker/encodings/DOMAIN/init.lp=, .e.g. =./checker/encodings/default/= for the default + domain - - stored in =./checker/encodings//actions= + 3. <>the types of action laws to verify, that is, - 2. /action effects/: effects after an action execution and the state - of the environment + - /action preconditions/ and /related inertial abnormals/ stored in + =./checker/encodings/DOMAIN/ACTION= for each action type =ACTION=, e.g. for the default + domain's action types =move=, =pickup=, =putdown= and =deliver=, the respective encodings are + #+BEGIN_SRC shell + ./checker/encodings/default/action-move.lp + ./checker/encodings/default/action-pickup.lp + ./checker/encodings/default/action-putdown.lp + ./checker/encodings/default/action-deliver.lp + #+END_SRC - - stored in =./checker/encodings//effects= + - /static laws/ stored in =./checker/encodings/DOMAIN/static.lp=, + e.g. =./checker/encodings/default/static.lp= for the default domain - 3. /static laws/: state constraints and transitions solely based on - the current state of the environment (fluents) + 4. the goal condition stored in =./checker/encodings/DOMAIN/goal.lp=, .e.g. for the default, + =./checker/encodings/default/= + + For each =DOMAIN=, all [[laws][action law encodings]] are then integrated via =#include= directives in the + encoding =./checker/encodings/DOMAIN/checker.lp=, .e.g. =./checker/encodings/default/checker.lp= + for the default domain. + + +* Currently Supported Domains + + At present we support the following problem domains: + - the [[file:~/logistics/ASPRILO/public/asprilo/docs/specification.org::#cid:b0f981f8-3202-42c0-a46e-aa6f1a52629b][default domain]] + + checker encodings at =./checker/encodings/default/= + - the default domain in conjunction with the [[file:~/logistics/ASPRILO/public/asprilo/docs/specification.org::#cid:49448523-5e9b-4ed2-ac1a-6754d838b85c]['disregard of product quantities' (DPQ)]] modification + + checker encodings at =./checker/encodings/dpq= - - stored in=./checker/encodings//states= * How To Use :PROPERTIES: :CUSTOM_ID: checker_how-to-use :END: -* Example Invocations - :PROPERTIES: - :CUSTOM_ID: checker_example-invocations - :END: + In general, within a problem domain =DOMAIN=, to check a plan file =PLAN= for an instance file + =INSTANCE= run + + #+BEGIN_SRC shell + clingo ./checker/encodings/DOMAIN/checker.lp INSTANCE PLAN + #+END_SRC + + Any inconsistencies will then be indicated by =err/3= atoms in the answer set, which are defined + in the [[*Encoding Structure][checker's encoding files]]. Moreover, =err/3= facts adhere to the format + + #+BEGIN_SRC prolog + err(FileID, CheckID, Parameters) + #+END_SRC + + where + 1. =FileID= indicates the encoding file in which the yielded =err/3= atom is defined + 2. =CheckID= indicates the specific 'check', i.e., a rule that defines the =err/3= atom + 3. =Parameters= the relevant term parameters in the body of the rule + + + E.g., for the default domain and instance =./examples/default/instance.asp=, the (invalid) plan + =./examples/default/wrong_outcome.txt= can be checked via + + #+BEGIN_SRC shell + clingo ./checker/encodings/default/checker.lp ./examples/default/instance.asp \ + ./examples/default/wrong_outcome.txt --out-ifs="\n"|grep err + #+END_SRC + + which yields: + + #+BEGIN_SRC prolog + err(goal,unfilledOrder,(3,3,1,11)) + err(goal,unfilledOrder,(3,2,1,11)) + #+END_SRC + + Those =err/3= facts are defined in =./checker/encodings/default/goal= by rule + + #+BEGIN_SRC prolog + err(goal, unfilledOrder, (O, P, Q, H)) :- holds(object(order, O), value(line, (P, Q)), H); + horizon(H). + #+END_SRC + that indicates, that there are still unfulfilled orders at the end of the plan. Specifically, + - =err(goal,unfilledOrder,(3,3,1,11))= indicates that order =O = 3= still requires =Q = 1= units of + product =P = 3=. + - =err(goal,unfilledOrder,(3,2,1,11))= indicates that order =O = 3= still requires =Q = 1= units of + product =P = 2=. From 1e866aa5d3bb2b60acb48e697a309d713cc9bf0d Mon Sep 17 00:00:00 2001 From: Thomas-Otto Date: Tue, 18 Jul 2017 05:02:27 +0200 Subject: [PATCH 014/188] - order, task, item windows now will be added to the main window *they can be attached to and detached from the main window with the same keys as open them - added complete mode *asprilo is now the default mode - piping now handels 'satisfiable' and 'unsitisfiable' - bugfix: empty orders will now be removed from the model --- visualizer/scripts/visualizer | 69 +++++++++++++++---------- visualizer/visualizer/configuration.py | 4 +- visualizer/visualizer/visualizerItem.py | 2 + 3 files changed, 47 insertions(+), 28 deletions(-) diff --git a/visualizer/scripts/visualizer b/visualizer/scripts/visualizer index fa03859..4d719f7 100755 --- a/visualizer/scripts/visualizer +++ b/visualizer/scripts/visualizer @@ -13,7 +13,7 @@ from visualizer.network import * from visualizer.gui import * from visualizer.configuration import * -VERSION = '0.10.3' +VERSION = '0.10.4' class VisualizerWindow(QMainWindow): def __init__(self): @@ -37,8 +37,8 @@ class VisualizerWindow(QMainWindow): type=str, default = '') self._argument_parser.add_argument('-m', '--mode', help='loads a preset of low level settings', - choices=['gtapf','asprilo'], - type=str, default = '') + choices=['gtapf','asprilo', 'complete'], + type=str, default = 'asprilo') self._argument_parser.add_argument('-s', '--start_solver', help='starts the default solver in the init file', action='store_true') @@ -111,12 +111,6 @@ class VisualizerWindow(QMainWindow): config.get('network', 'port_simulator'), self._simulator_socket) - self._order_widget = OrderWidget() - self._order_widget.set_model(self._model) - - self._product_window = ProductWindow() - self._product_window.set_model(self._model) - self._grid_size_dialog = GridSizeDialog() self._grid_size_dialog.set_model(self._model) self._grid_size_dialog.set_model_view(self._model_view) @@ -126,8 +120,20 @@ class VisualizerWindow(QMainWindow): self._control_splitter.set_model(self._model) self._splitter.addWidget(self._control_splitter) + self._order_widget = OrderWidget() + self._order_widget.set_model(self._model) + self._control_splitter.addWidget(self._order_widget) + self._order_widget.hide() + + self._product_window = ProductWindow() + self._product_window.set_model(self._model) + self._control_splitter.addWidget(self._product_window) + self._product_window.hide() + self._task_widget = TaskTable() self._task_widget.set_model(self._model) + self._control_splitter.addWidget(self._task_widget) + self._task_widget.hide() self._splitter.setSizes([200, 600, 200]) self._model_view.resize_to_fit() @@ -271,7 +277,7 @@ class VisualizerWindow(QMainWindow): action = QAction('Orders', self) action.setShortcut('Ctrl+O') action.setStatusTip('Show a window that lists all orders') - action.triggered.connect(self._order_widget.show) + action.triggered.connect(lambda: self.switch_widget(self._order_widget)) menu_windows.addAction(action) self.addAction(action) @@ -279,7 +285,7 @@ class VisualizerWindow(QMainWindow): action = QAction('Products', self) action.setShortcut('Ctrl+R') action.setStatusTip('Show a window that contains all products') - action.triggered.connect(self._product_window.show) + action.triggered.connect(lambda: self.switch_widget(self._product_window)) menu_windows.addAction(action) self.addAction(action) @@ -287,7 +293,7 @@ class VisualizerWindow(QMainWindow): action = QAction('Tasks', self) action.setShortcut('Ctrl+T') action.setStatusTip('Show a window that contains all tasks') - action.triggered.connect(self._task_widget.show) + action.triggered.connect(lambda: self.switch_widget(self._task_widget)) menu_windows.addAction(action) self.addAction(action) @@ -314,28 +320,27 @@ class VisualizerWindow(QMainWindow): self.addAction(action) def read_input(self): - answer = False + finish_answer = False found_answer = False lines = [] try: if sys.stdin in select.select([sys.stdin], [], [], 0)[0]: for line in sys.stdin.readlines(): - lines.append(line) - if answer and not found_answer: - self._asp_parser.add_program('input', line.replace(' ', '.')) - if line[len(line) - 1] == '\n': - answer = False - found_answer = True - self._asp_parser.add_program('input', '.') - self._asp_parser.parse() if line.lower().find('answer') != -1: - print 'satisfiable' - answer = True - if line.lower().find('unsatisfiable') != -1: - print 'unsatisfiable' - anser = True found_answer = True - if found_answer == False and len(lines) > 0: + elif line.lower().find('unsatisfiable') != -1: + print 'unsatisfiable' + elif line.lower().find('satisfiable') != -1: + print 'satisfiable' + else: + lines.append(line) + if found_answer and not finish_answer: + self._asp_parser.add_program('input', line.replace(' ', '.')) + if line[len(line) - 1] == '\n': + finish_answer = True + self._asp_parser.add_program('input', '.') + self._asp_parser.parse() + if not found_answer and len(lines) > 0: for line in lines: self._asp_parser.add_program('input', line) self._asp_parser.parse() @@ -343,6 +348,16 @@ class VisualizerWindow(QMainWindow): print error print 'Failed to read from stdin' + def switch_widget(self, widget): + if not widget.isVisible(): + widget.show() + return + if widget.parent() == self._control_splitter: + widget.setParent(None) + widget.show() + else: + widget.setParent(self._control_splitter) + def open_file_dialog(self, mode, function): self._file_dialog.setAcceptMode(mode) try: diff --git a/visualizer/visualizer/configuration.py b/visualizer/visualizer/configuration.py index b626c50..c2aa00b 100644 --- a/visualizer/visualizer/configuration.py +++ b/visualizer/visualizer/configuration.py @@ -211,7 +211,9 @@ def __init__(self): def init_defaults(self, args = None): if args is None: - self._file_name = os.path.dirname(sys.argv[0]) + '/config/mdefault.cfg' + return + elif args.mode == 'complete': + self._file_name = os.path.dirname(sys.argv[0]) + '/config/mcomplete.cfg' self._values = { ('features', 'orders') : ConfigEntry(self._read_bool_from_config, True, str, 'orders'), ('features', 'products') : ConfigEntry(self._read_bool_from_config, True, str, 'products'), diff --git a/visualizer/visualizer/visualizerItem.py b/visualizer/visualizer/visualizerItem.py index e7a37f3..7dfe266 100644 --- a/visualizer/visualizer/visualizerItem.py +++ b/visualizer/visualizer/visualizerItem.py @@ -65,6 +65,8 @@ def remove_request(self, product_id): for temp_request in self._requests: if str(temp_request.product_id) == str(product_id): self._requests.remove(temp_request) + if len(self._requests) == 0: + self._model.remove_item(self) return def add_request(self, product_id, requested_amount): From d1bae3ec8929e437fbf107c06b4d0d3d195ea9ad Mon Sep 17 00:00:00 2001 From: Thomas-Otto Date: Wed, 26 Jul 2017 10:48:56 +0200 Subject: [PATCH 015/188] -add readme file -add support for online simulators -update support for onlie solvers -bugfix: sockets should close correctly now --- visualizer/README.md | 63 ++++++++++++++++++++++++ visualizer/scripts/network.py | 12 ++++- visualizer/scripts/simulator.py | 14 ++++-- visualizer/scripts/solver_inc.py | 1 + visualizer/scripts/solver_interactive.py | 2 +- visualizer/scripts/visualizer | 8 +-- visualizer/visualizer/model.py | 37 ++++++++++++-- visualizer/visualizer/network.py | 36 ++++++++++---- visualizer/visualizer/parser.py | 3 +- 9 files changed, 151 insertions(+), 25 deletions(-) create mode 100644 visualizer/README.md diff --git a/visualizer/README.md b/visualizer/README.md new file mode 100644 index 0000000..da9f3c0 --- /dev/null +++ b/visualizer/README.md @@ -0,0 +1,63 @@ +#Visualizer + +The visualizer is a tool to visualize asprilo problems. It also provides tools to edit and create asprilo instances. For more informations to the general asprilo problem see: + +#Requirments + +You need Python 2.7, PYQT 5.0 or newer and clingo 5.2 or newer to run the visualizer. + +#Execution + +You can run the visualizer by calling `visualizer` in your console. + +##Arguments + +The visualizer accepts following arguments. You can aslo call `visualizer --help` for more information: + +*`-d/--directory`: Sets the default directory. The file browser will show directory and files in this directory and all file dialogs for saving and loading files will have this as default directory. +*`-t/--templates`: A list of files that will be loaded at the beginning. +*`-l/-layouts`: Same as `-t/--templates`. +*`-p/--plans`: Same as `-t/--templates`. +*`-s/--start_solver`: Starts the default solver at the beginning and connect the visualizer to it. The default solver is the solver described in the setting file. +*`-m/--mode`: Starts the visualizer in a specific mode. A mode is a preset of low-level settings. It turns on and off some features. By default all features are activated. Possible modes are currently gtapf, complete and asprilo. + +##Piping + +The visualizer accepts piping from another program such as clingo. +E.g run `clingo [ARGUMENTS] | visualizer [ARGUMENTS]` to pipe a clingo solution directly to the visualizer. +Your encoding should contain `#show init/2.` and `#show occurs/3.` statements to pipe correct. It also accepts input in asp format. +E.g: +init(object(robot, 1), value(at, (1,1))). +occurs(object(robot, 1), action(move, (0,1), 1)). + +#Loading Instances/Plans + +The visualizer provides different ways to load an instance or a plan: +1. Load an instance/plan with the arguments `-t/--templates`, `-l/-layouts` or `-p/--plans`. +2. Pipe an instance/plan into the visualizer. +3. Use the file dialogs `File->Load instance [STRG + L]` or `File->Load plan [STRG + V]` to load an instance or a plan. +4. Double left click on an file in the file browser to load an instance or right click and then press `load instance` or `load plan` to load an instance or a plan. +5. Right click on a file in the file browser and than press `parse file` to load an instance or a plan. + +If you load an instance via 3 or 4 the visualizer will override the current model with the loaded instance. If you load a plan via 3 or 4 it will override the current actions with the loaded plan. This will not delete objects like shelves or robots. You should load a compatible instance before loading a plan. +If you load an instance or a plan via 5 this will override nothing. It will add every loaded atom from the file to the current model. +When an instance is loaded a png file that represents the instance will be created automatically. This can be disabled in the settings. To create png files of all instance (.lp) files in one directories and all sub directories use `File->Create all png files`. +The file browser will only be shown if you use the `-d/--directory` arguments. It can also be toggled on and off in the menu `Tools->File browser [STRG + F]`. + +#Control + +Use the `> [UP]` button to go one step forward in the plan or the `< [Down]` button to go one step backward. You can pause and unpause the automated visualisation with the `|> [Space]` or `|| [Space]` buttons. The `|<|< [Left]` and `|>|> [Right]` buttons speeds the visualisation up or slows it down. To skip to the end of the plan or restart it use the `>|` and `|<` buttons. You can use the mouse wheel, the `+` and `-` buttons or the `+` and `-` keys to zoom in and zoom out. + +#Parser + +You can open the parser with the `[STRG + P]` keys or the menu `Tools->Parser`. The parser shows all loaded instances in the left text field. If more than one instance is loaded you can use the tabs to switch between them. The instances can be modified. The right text field shows all atoms that are currently in the solvers model. Use the `reset grounder` button to clear them. The `reset actions` button will clear all current actions in the current model while the `reset model` button will clear the whole model including all objects and all actions. You can reload the current shown program with `reload program` and delete it with `delete program`. `delete programs` will delete all current loaded instances from the parser and will reload all defalut files that are set in the settings. `parse programm` will sent all instances to the solver and start the solving process. The resulting model will be added to the current model. To load an instance use the methods described at [Loading Instances/Plans](#Loading Instances/Plans). + +#Editor + +The visualizer allows also the editing of instances. You can [load an instance](#Loading Instances/Plans) or create a new one `File->New instance [STRG + N]`. To remove or add objects right click on a node on the model display. Objects can also be moved via drag and drop from one node to another. Use the grid size window `Tools->Grid Size` to adjust the grid of the instance. Products can be edited in the orders window `Tools->Orders`. To add a product right click on a shelf and choose `add product`. right click on a product entry and then click on `remove product` to remove a product from a shelf. Orders can be edited the same way via the orders window `Tools->orders`. You can edit an instance until the instance was sended to the solver or a plan was loaded. As soon as one `occurs` atom was added to the model it is no longer possible to edit it. To save an instance use `File->Save instance [STRG + I]`. To save a plan use `File->Save plan [STRG + A]`. + +#Solver + +You can use a solver script to solve instances and get plans as solution. The visualizer provides a few default solver scripts and encodings. You can find them in the scipts directory. A solver script can be started separately or with the `Network->Initialize solver` option. If you start it from the visualizer you can enter a command line to start the solver and it will be connected automatically to the visualizer. Use`Network->Solve` now to send the current model to the solver. Enter the port and host of the the solver in the opened dialog. For a local solver use 127.0.0.1 as host. You can use `Network->Fast solve` or `[STRG + S]` keys to skip the host and port dialog. In this case the visualizer will choose default values. As soon as the solver sends a solution to the visualizer the visualizer can display the received actions. If you load a new instance while the solver is solving this will not reset the solver and you can receive wrong actions. To reset the solver you must send a new instance to it. + +#Simulator diff --git a/visualizer/scripts/network.py b/visualizer/scripts/network.py index 80a1109..6042eaa 100644 --- a/visualizer/scripts/network.py +++ b/visualizer/scripts/network.py @@ -46,7 +46,7 @@ def receive(self, time_out): if self._connection is None: return -1 try: - if self.is_ready_to_read(4.0): + if self.is_ready_to_read(time_out): while True: new_data = self._connection.recv(2048) if not new_data or new_data == '': @@ -60,7 +60,7 @@ def receive(self, time_out): return 0 except socket.error as error: - self._close() + self.close() print error return -1 @@ -87,11 +87,19 @@ def connect(self): def close(self): if self._connection is not None: + try: + self._connection.shutdown(socket.SHUT_RDWR) + except socket.error: + pass self._connection.close() self._connection = None print 'close ' + self._name if self._socket is not None: + try: + self._socket.shutdown(socket.SHUT_RDWR) + except socket.error: + pass self._socket.close() self._socket = None diff --git a/visualizer/scripts/simulator.py b/visualizer/scripts/simulator.py index c4b59c2..3f77cb0 100755 --- a/visualizer/scripts/simulator.py +++ b/visualizer/scripts/simulator.py @@ -2,7 +2,7 @@ from network import * import clingo -VERSION = '0.1.0' +VERSION = '0.1.2' class Simulator(Network): def __init__(self): @@ -27,15 +27,21 @@ def load(self, file_name): self._control.solve(on_model = self.on_model) def on_connect(self): + self.send('%$RESET.') self.send_step(0) def on_model(self, model): for atom in model.symbols(atoms=True): - print atom if (atom.name == 'init' - and len(atom.arguments) == 3 - and atom.arguments[0].name == 'object' + and len(atom.arguments) == 3 + and atom.arguments[0].name == 'object' and atom.arguments[1].name == 'value'): + step = 0 + try: + step = int(atom.arguments[2].number) + except Exception as error: + print error + continue if step not in self._to_send: self._to_send[step] = [] self._to_send[step].append('init(' + str(atom.arguments[0]) + ',' diff --git a/visualizer/scripts/solver_inc.py b/visualizer/scripts/solver_inc.py index 28d055b..3bd3fd3 100755 --- a/visualizer/scripts/solver_inc.py +++ b/visualizer/scripts/solver_inc.py @@ -26,6 +26,7 @@ def solve(self): while(True): if self.is_ready_to_read(): solve_future.cancel() + print 'solving interrupted' return -1 finished = solve_future.wait(5.0) if finished: diff --git a/visualizer/scripts/solver_interactive.py b/visualizer/scripts/solver_interactive.py index 931b7b0..843f685 100755 --- a/visualizer/scripts/solver_interactive.py +++ b/visualizer/scripts/solver_interactive.py @@ -22,7 +22,7 @@ def on_data(self, data): for atom in self._inits: self._control.add('base', [], atom + '.') - for ii in xrange(0, self._sended): + for ii in xrange(0, self._sended + 1): if ii in self._to_send: for atom in self._to_send[ii]: self._control.add('base', [], str(atom) + '.') diff --git a/visualizer/scripts/visualizer b/visualizer/scripts/visualizer index 4d719f7..67a85f8 100755 --- a/visualizer/scripts/visualizer +++ b/visualizer/scripts/visualizer @@ -54,11 +54,13 @@ class VisualizerWindow(QMainWindow): self._asp_parser = AspParser() self._model = self._asp_parser.get_model() - self._solver_socket = SolverSocket() - self._simulator_socket = SimulatorSocket() - self._asp_parser.set_solver(self._solver_socket) + self._simulator_socket = SimulatorSocket() + self._model.add_socket(self._simulator_socket) self._simulator_socket.set_parser(self._asp_parser) + + self._solver_socket = SolverSocket() + self._asp_parser.set_solver(self._solver_socket) self._solver_socket.set_parser(self._asp_parser) self._solver_socket.set_model(self._model) diff --git a/visualizer/visualizer/model.py b/visualizer/visualizer/model.py index 54f6e9d..5bdac24 100644 --- a/visualizer/visualizer/model.py +++ b/visualizer/visualizer/model.py @@ -24,6 +24,8 @@ def __init__(self): self._current_step = 0 self._displayed_steps = -1 + self._notifier = None + def clear(self): for window in self._windows: if isinstance(window, ModelView): @@ -86,9 +88,9 @@ def accept_new_items(self, item_kinds = None): self._add_item2(item) for socket in self._sockets: for item in add_items: - socket.send(item.to_init_str()) + socket.model_expanded(item.to_init_str()) if len(add_items) > 0: - socket.send('\n') + socket.model_expanded('\n') def discard_new_items(self, item_kinds = None): if item_kinds == None: @@ -262,17 +264,42 @@ def create_item(self, item_kind, ID = None, add_immediately = False): def update(self): if self._current_step > self._num_steps or self._num_steps == 0: return self._current_step + for socket in self._sockets: + if socket.is_waiting(): + return self._current_step for items_dic in self._graphic_items.itervalues(): for item in items_dic.itervalues(): item.do_action(self._current_step) - if self._displayed_steps < self._current_step: + + if self._displayed_steps < self._current_step and len(self._sockets) > 0: self._displayed_steps = self._current_step - for socket in self._sockets: - socket.send('%$done(' + str(self._current_step) + ').\n') + iterator = iter(self._sockets) + value = iterator.next() + value.done_step(self._current_step) + self.notify_sockets(iterator, value) + self._current_step += 1 self.update_windows() return self._current_step + def notify_sockets(self, iterator, value): + if value.is_waiting(): + if self._notifier is not None: + self._notifier.stop() + + self._notifier = QTimer() + self._notifier.setSingleShot(True) + self._notifier.timeout.connect(lambda: self.notify_sockets(iterator, value)) + self._notifier.start(100) + return + else: + try: + value = iterator.next() + except StopIteration: + return + value.done_step(self._current_step) + self.notify_sockets(iterator, value) + def undo(self): if self._current_step == 0: return self._current_step diff --git a/visualizer/visualizer/network.py b/visualizer/visualizer/network.py index 015d346..51c931b 100644 --- a/visualizer/visualizer/network.py +++ b/visualizer/visualizer/network.py @@ -15,6 +15,7 @@ def __init__(self, default_host = '127.0.0.1', default_port = 5000, socket_name self._socket_name = socket_name self._thread = None self._parser = None + self._waiting = False def __del__(self): self.close() @@ -29,9 +30,9 @@ def run_script(self, command, port = None): if port is not None: self.connect('127.0.0.1', port) - def join(self): + def join(self, wait_time): if self._thread is not None: - self._thread.join(30.0) + self._thread.join(wait_time) self._thread = None def run_connection(self): @@ -75,7 +76,16 @@ def send(self, msg): if self._s is None: return self._s.send(msg) - + + def done_step(self, step): + if self._s is None: + return + self._waiting = True + self._s.send('%$done(' + str(step) + ').\n') + + def model_expanded(self, msg): + pass + def _receive_data(self): breakLoop = False data = '' @@ -104,9 +114,13 @@ def close(self): self._timer.stop() if self._s is not None: print 'Close connection to ' + self._socket_name + try: + self._s.shutdown(socket.SHUT_RDWR) + except socket.error: + pass self._s.close() self._s = None - self.join() + self.join(10) def is_connected(self): return self._s is not None @@ -114,6 +128,9 @@ def is_connected(self): def script_is_running(self): return self._thread is not None + def is_waiting(self): + return self._waiting + def get_host(self): return self._host @@ -131,6 +148,9 @@ def set_model(self, model): if model is not None: self._model.add_socket(self) + def model_expanded(self, msg): + self.send(msg) + def receive(self): if self._s is None or self._parser is None or self._model is None: return -1 @@ -140,13 +160,11 @@ def receive(self): return if data == '': return - + self._waiting = False for str_atom in data.split('.'): if len(str_atom) != 0 and not (len(str_atom) == 1 and str_atom[0] == '\n'): if str_atom == '%$RESET': self._parser.clear_model_actions(True) - elif str_atom[0] == '\n': - pass else: self._parser.on_atom(clingo.parse_term(str_atom)) self._model.update_windows() @@ -179,8 +197,8 @@ def receive(self): return if data == '': return - - for str_atom in data.split('.'): + self._waiting = False + for str_atom in data.split('.'): if len(str_atom) != 0 and not (len(str_atom) == 1 and str_atom[0] == '\n'): if str_atom == '%$RESET': self._parser.clear_model() diff --git a/visualizer/visualizer/parser.py b/visualizer/visualizer/parser.py index 7a97282..5e7461e 100644 --- a/visualizer/visualizer/parser.py +++ b/visualizer/visualizer/parser.py @@ -98,7 +98,7 @@ def _on_init_atom(self, obj, value): value_name = str(value.arguments[0]) value_value = value.arguments[1] - item = self._model.get_item(kind, ID, True, True) + item = self._model.get_item(kind, ID, True, self._model.get_editable()) if item is not None: result = item.parse_init_value(value_name, value_value) @@ -131,6 +131,7 @@ def _on_init_atom(self, obj, value): print ('invalid init: init(' + str(obj) + ', ' + str(value) + ')') def done_instance(self): + self._model.accept_new_items() self._model.update_windows() if (self._solver is not None and configuration.config.get('visualizer', 'auto_solve')): From 99d2dd3a9eba94df4f057a2fbfa800e8a652410c Mon Sep 17 00:00:00 2001 From: Thomas-Otto Date: Wed, 26 Jul 2017 14:36:24 +0200 Subject: [PATCH 016/188] -bugfix --- visualizer/visualizer/model.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/visualizer/visualizer/model.py b/visualizer/visualizer/model.py index 5bdac24..b13148f 100644 --- a/visualizer/visualizer/model.py +++ b/visualizer/visualizer/model.py @@ -276,20 +276,20 @@ def update(self): iterator = iter(self._sockets) value = iterator.next() value.done_step(self._current_step) - self.notify_sockets(iterator, value) + self.notify_sockets(iterator, value, self._current_step) self._current_step += 1 self.update_windows() return self._current_step - def notify_sockets(self, iterator, value): + def notify_sockets(self, iterator, value, step): if value.is_waiting(): if self._notifier is not None: self._notifier.stop() self._notifier = QTimer() self._notifier.setSingleShot(True) - self._notifier.timeout.connect(lambda: self.notify_sockets(iterator, value)) + self._notifier.timeout.connect(lambda: self.notify_sockets(iterator, value, step)) self._notifier.start(100) return else: @@ -297,8 +297,8 @@ def notify_sockets(self, iterator, value): value = iterator.next() except StopIteration: return - value.done_step(self._current_step) - self.notify_sockets(iterator, value) + value.done_step(step) + self.notify_sockets(iterator, value, step) def undo(self): if self._current_step == 0: From 660e8fca6c5f23fea74f81ec3d1a1318ccae0499 Mon Sep 17 00:00:00 2001 From: Philipp Obermeier Date: Wed, 19 Jul 2017 14:57:01 +0200 Subject: [PATCH 017/188] Adding domain levels to Readme WIP --- docs/specification.org | 194 +++++++++++++++++++++++++---------------- 1 file changed, 119 insertions(+), 75 deletions(-) diff --git a/docs/specification.org b/docs/specification.org index d8b77fc..b67a618 100644 --- a/docs/specification.org +++ b/docs/specification.org @@ -10,7 +10,7 @@ - provide a example instance and plan -* Default Problem Domain +* Default Problem Domain (DEF) :PROPERTIES: :ID: 4b70ec8c-54b2-454c-a1ce-a476550c2124 :CUSTOM_ID: cid:b0f981f8-3202-42c0-a46e-aa6f1a52629b @@ -205,12 +205,17 @@ :CUSTOM_ID: cid:bbacc203-29c4-489f-8661-95cf4b599fdd :END: - Based on the [[#cid:b0f981f8-3202-42c0-a46e-aa6f1a52629b][default problem domain]], we can envision various additional modifications. For each - modification, we will subsequently describe it and enumerate the additional and changed instance - characteristics in comparison to the default problem. Besides, we will also point out if a - modification changes the overall goal of the problem. + Based on the [[#cid:b0f981f8-3202-42c0-a46e-aa6f1a52629b][default problem domain]], we can envision various additional modifications. For each, + we will subsequently describe it and enumerate the additional and changed instance characteristics + in comparison to the default problem. Besides, we will also point out if a modification changes + the overall goal of the problem. -** Disregard of Product Quantities (DPQ) + In the heading of a paragraph that describes a modification, its acronym is given in parentheses. + Further, if the modification represents a simplification of the default domain, it is additionally + labelled as such within the parentheses too. + + +** Disregard of Product Quantities (DPQ/Simplification) :PROPERTIES: :CUSTOM_ID: cid:49448523-5e9b-4ed2-ac1a-6754d838b85c :END: @@ -229,6 +234,30 @@ Not applicable here. +** Instant Concurrent Deliveries (ICD/Simplification) + :PROPERTIES: + :CUSTOM_ID: cid:f8d8f6b9-771a-4b1d-a20d-1ce03f96086b + :END: + + This is a simplification of the default domain in the sense that for a robot at a picking + station, all deliveries can be processed in parallel and within a single time step. + +** Movements Only (MOO/Simplification) + :PROPERTIES: + :CUSTOM_ID: cid:8dcd778b-8504-449d-9811-39ec61c50cbb + :END: + + This is a simplification of the default domain in the sense the only action that robots can + perform is move, i.e., there are no pickup, putdown or delivery actions in plans. With that, we + need to define when a robot /implicitly/ picks up or puts down a shelf as well as delivers items at + a picking station: specifically, a robot + - picks up a shelf as soon as he is beneath one and not carrying it already; + - when at a picking station and carrying a shelf, all possible (with respect to unfilled order + lines and available quantities on the shelf) deliveries are concurrently executed in a single + time step + - when carrying a shelf, can only put it down at the same node where it was originally picked-up. + + ** Product Capacity for Robots and Shelves Based on Quantity (CAQ) :PROPERTIES: :CUSTOM_ID: cid:9828decd-6d59-4ccc-94c2-847b3a6b7a08 @@ -410,25 +439,40 @@ * Supported Combinations of Modifications - In table below, we illustrate combinations of two problem modifications that we (plan to) - support by our tools. + In the table below, we list all (planned to be) supported combinations of modifications. Further, + our supported combinations are chosen such that they represent a well-ordered set + + #+CAPTION: Supported combinations of problem modifications + | "Distance" to DEF | Combinations | + |-------------------+-----------------------| + | / | <> | + | 0 | DEF | + | -1 | DEF + DPQ | + | -2 | DEF + DPQ + ICD | + | - \infty | DEF + DPQ + ICD + MOO | + + +** Principally Possible Combinations + + In table below, we illustrate pair-wise combinations of problem modifications that we consider + possible in principle but not necessarily (planned to be) supported by our tools. - #+CAPTION: Supported pairwise combinations of problem modifications. - | | DPQ | CAQ | CAW | CAV | EMA | REP | OEX | OPS | OOP | - |-----+------------+------------+------------+------------+------------+------------+------------+------------+------------| - | / | < | | | | | | | | > | - | DPQ | | | | | \checkmark | | \checkmark | \checkmark | \checkmark | - | CAQ | | | | | \checkmark | \checkmark | \checkmark | \checkmark | \checkmark | - | CAW | | | | \checkmark | \checkmark | \checkmark | \checkmark | \checkmark | \checkmark | - | CAV | | | \checkmark | | \checkmark | \checkmark | \checkmark | \checkmark | \checkmark | - | EMA | \checkmark | \checkmark | \checkmark | \checkmark | | \checkmark | \checkmark | \checkmark | \checkmark | - | REP | | \checkmark | \checkmark | \checkmark | \checkmark | | \checkmark | \checkmark | \checkmark | - | OEX | \checkmark | \checkmark | \checkmark | \checkmark | \checkmark | \checkmark | | \checkmark | \checkmark | - | OPS | \checkmark | \checkmark | \checkmark | \checkmark | \checkmark | \checkmark | \checkmark | | \checkmark | - | OOP | \checkmark | \checkmark | \checkmark | \checkmark | \checkmark | \checkmark | \checkmark | \checkmark | | + #+CAPTION: Principally possible pairwise combinations of problem modifications. + | | DPQ | CAQ | CAW | CAV | EMA | REP | OEX | OPS | OOP | + |-----+------------+------------+------------+------------+------------+------------+------------+------------+------------| + | / | < | | | | | | | | > | + | DPQ | | | | | \checkmark | | \checkmark | \checkmark | \checkmark | + | CAQ | | | | | \checkmark | \checkmark | \checkmark | \checkmark | \checkmark | + | CAW | | | | \checkmark | \checkmark | \checkmark | \checkmark | \checkmark | \checkmark | + | CAV | | | \checkmark | | \checkmark | \checkmark | \checkmark | \checkmark | \checkmark | + | EMA | \checkmark | \checkmark | \checkmark | \checkmark | | \checkmark | \checkmark | \checkmark | \checkmark | + | REP | | \checkmark | \checkmark | \checkmark | \checkmark | | \checkmark | \checkmark | \checkmark | + | OEX | \checkmark | \checkmark | \checkmark | \checkmark | \checkmark | \checkmark | | \checkmark | \checkmark | + | OPS | \checkmark | \checkmark | \checkmark | \checkmark | \checkmark | \checkmark | \checkmark | | \checkmark | + | OOP | \checkmark | \checkmark | \checkmark | \checkmark | \checkmark | \checkmark | \checkmark | \checkmark | | - A combination of more than two modifications is supported if there is a supported pairwise - combination for all modifications in question. + A combination of more than two modifications is possible if there is a possible pairwise + combination for all modifications in question. * Classification of Instances @@ -443,11 +487,11 @@ #+BEGIN_SRC dot :file img/dot_classification.png :cmdline -Kdot -Tpng digraph { - subgraph clusterA {label="1. Problem Scope\n(e.g. Default Domain + DPQ)" - subgraph clusterB {label="2. Warehouse Characteristics\n(e.g. 10x10 grid, 20 shelves, 2 picking stations, 5 robots, default interiors layout)" - node [shape=box] "3. Order Set Characteristics\n(e.g. 10 orders, 2 order lines in avg, 40% of available products ordered)"; - } - } + subgraph clusterA {label="1. Problem Scope\n(e.g. Default Domain + DPQ)" + subgraph clusterB {label="2. Warehouse Characteristics\n(e.g. 10x10 grid, 20 shelves, 2 picking stations, 5 robots, default interiors layout)" + node [shape=box] "3. Order Set Characteristics\n(e.g. 10 orders, 2 order lines in avg, 40% of available products ordered)"; + } + } } #+END_SRC @@ -505,7 +549,7 @@ ~~, e.g. ~object(robot, 34)~ for a robot with ID 34 - function ~value~ specifies that the object's attribute ~~ has value ~~ e.g. #+BEGIN_SRC prolog - init(object(robot, 34), value(at, (2,3))). + init(object(robot, 34), value(at, (2,3))). #+END_SRC states that the robot 34 is at x/y-location (2,3). @@ -532,14 +576,14 @@ - function ~value~ specifies that the subtype's attribute ~~ has value ~~, e.g.for a given object-type ~robot~ #+BEGIN_SRC prolog - init(subtype(robot, 3), value(maxEnergy, 250)). + init(subtype(robot, 3), value(maxEnergy, 250)). #+END_SRC states that robots of object-subtype 3 have a battery with maximum energy capacity of 250. To declare that an object-type belongs to a object-subtype the attribute ~subtype~ is used, e.g. #+BEGIN_SRC prolog - init(object(robot, 34), value(subtype, 3)). + init(object(robot, 34), value(subtype, 3)). #+END_SRC states that robot 34 is of object-subtype 3 and hence "inherits" the maximum energy capacity of 250. @@ -565,8 +609,8 @@ occupied by robots and shelves, it suffices to state the grid's x,y-dimension via attribute ~xsize~ and ~ysize~, e.g. #+BEGIN_SRC prolog - init(object(grid,1), value(xsize, 45)). - init(object(grid,1), value(ysize, 35)). + init(object(grid,1), value(xsize, 45)). + init(object(grid,1), value(ysize, 35)). #+END_SRC states that the x,y-dimensions are 45 and 35. @@ -575,8 +619,8 @@ of a warehouse grid can be occupied by robots and shelves, each of those nodes has to be explicitly stated via attribute ~at~, e.g. #+BEGIN_SRC prolog - init(object(node, 1), value(at, (1,5))). - init(object(node, 2), value(at, (2,5))). + init(object(node, 1), value(at, (1,5))). + init(object(node, 2), value(at, (2,5))). #+END_SRC states that there exist grid nodes 1 and 2 at coordinates (1,5) and (2,5), resp. - Remark: in the problem encoding, ~node~ facts can be seen as generalization of ~grid~ in the @@ -597,12 +641,12 @@ - The grid position of a robot is indicated by attribute ~at~, e.g. #+BEGIN_SRC prolog - init(object(robot, 1), value(at, (2,3))). + init(object(robot, 1), value(at, (2,3))). #+END_SRC states that robot 1 is at location (2,3). - A situation where a robot initially carries a shelf is indicated by attribute ~carries, e.g. #+BEGIN_SRC prolog - init(object(robot, 2), value(carries, 5)). + init(object(robot, 2), value(carries, 5)). #+END_SRC states that robot 2 is carrying shelf 5. @@ -611,12 +655,12 @@ - The battery level of a robot is indicated by attribute ~energy~, e.g. #+BEGIN_SRC prolog - init(object(robot, 1), value(energy, 23)). + init(object(robot, 1), value(energy, 23)). #+END_SRC states that robot 1 has battery level 23. - The maximum energy capacity of robot's battery is indicated by attribute ~maxEnergy~, e.g. #+BEGIN_SRC prolog - init(object(robot, 1), value(maxEnergy, 250)). + init(object(robot, 1), value(maxEnergy, 250)). #+END_SRC states that robots 1 has a battery with maximum energy capacity of 250. @@ -626,7 +670,7 @@ - The maximum number of product units a robot can carry is indicated by attribute ~maxQuantity~, e.g. #+BEGIN_SRC prolog - init(object(robot, 1), value(maxQuantity, 20)). + init(object(robot, 1), value(maxQuantity, 20)). #+END_SRC states that robots 1 can carry up to 20 product units. @@ -635,7 +679,7 @@ - The maximum weight a robot can carry is indicated by attribute ~maxWeight~, e.g. #+BEGIN_SRC prolog - init(object(robot, 1), value(maxWeight, 500)). + init(object(robot, 1), value(maxWeight, 500)). #+END_SRC states that robots 1 can carry a payload weight of up to 500. @@ -644,7 +688,7 @@ - The maximum volume a robot can carry is indicated by attribute ~maxVolume~, e.g. #+BEGIN_SRC prolog - init(object(robot, 1), value(maxVolume, 267)). + init(object(robot, 1), value(maxVolume, 267)). #+END_SRC states that robots 1 can carry a payload volume of up to 267. @@ -670,7 +714,7 @@ - The grid position of a shelf is indicated by attribute ~at~, e.g. #+BEGIN_SRC prolog - init(object(shelf, 1), value(at, (2,3))). + init(object(shelf, 1), value(at, (2,3))). #+END_SRC states that shelf 1 is at location (2,3). @@ -680,7 +724,7 @@ - The quantitative capacity of a shelf is indicated by attribute ~maxQuantity~, e.g. #+BEGIN_SRC prolog - init(object(shelf, 1), value(maxQuantity, 20)). + init(object(shelf, 1), value(maxQuantity, 20)). #+END_SRC states that shelf 1 has a maximum quantitative capacity of 20. @@ -690,7 +734,7 @@ - The weight-based capacity of a shelf is indicated by attribute ~maxWeight~, e.g. #+BEGIN_SRC prolog - init(object(shelf, 1), value(maxWeight, 23)). + init(object(shelf, 1), value(maxWeight, 23)). #+END_SRC states that shelf 1 has a maximum weight capacity of 23. @@ -700,7 +744,7 @@ - The volume-based capacity of a shelf is indicated by attribute ~maxVolume~, e.g. #+BEGIN_SRC prolog - init(object(shelf, 1), value(maxVolume, 267)). + init(object(shelf, 1), value(maxVolume, 267)). #+END_SRC states that shelf 1 has a maximum volume capacity of 267. @@ -726,7 +770,7 @@ - A shelf on which a product is stored on is indicated by attribute ~on~, e.g., #+BEGIN_SRC prolog - init(object(product, 45), value(on, (5, 280)). + init(object(product, 45), value(on, (5, 280)). #+END_SRC states that 280 units of product 45 are on shelf 5. @@ -736,7 +780,7 @@ - In case product quantities are ignored, the value of ~on~ is a single integer indicating the shelf, e.g. #+BEGIN_SRC prolog - init(object(product, 45), value(on, 5). + init(object(product, 45), value(on, 5). #+END_SRC states that product 45 is on shelf 5 in unlimited quantity. @@ -745,7 +789,7 @@ - The weight of a product is indicated by attribute ~weight~, e.g. #+BEGIN_SRC prolog - init(object(product, 1), value(weight, 4)). + init(object(product, 1), value(weight, 4)). #+END_SRC states that product 1 has weight 4. @@ -754,7 +798,7 @@ - The volume of a product is indicated by attribute ~volume~, e.g. #+BEGIN_SRC prolog - init(object(product, 1), value(volume, 15)). + init(object(product, 1), value(volume, 15)). #+END_SRC states that product 1 has a volume 15. @@ -781,8 +825,8 @@ - Lines of an order, i.e., requests of products in a certain quantity, are indicated by attribute ~line~, e.g., #+BEGIN_SRC prolog - init(object(order, 7), value(line, (467, 2))). - init(object(order, 7), value(line, (77, 12))). + init(object(order, 7), value(line, (467, 2))). + init(object(order, 7), value(line, (77, 12))). #+END_SRC states that order 7 requests 2 units of product 467, and 12 units of product 77. @@ -790,7 +834,7 @@ - The picking station of an order is indicated by attribute ~pickingStation~, e.g. #+BEGIN_SRC prolog - init(object(order, 7), value(pickingStation, 4). + init(object(order, 7), value(pickingStation, 4). #+END_SRC states that order 7 is assigned to picking station 4. @@ -798,7 +842,7 @@ - The expiration timeout of an order is indicated by attribute ~expirationTimeOut~, e.g. #+BEGIN_SRC prolog - init(object(order, 7), value(expirationTimeOut, 20). + init(object(order, 7), value(expirationTimeOut, 20). #+END_SRC states that order 7 expires 20 time steps after the time step of its arrival. @@ -823,7 +867,7 @@ - The grid position of a picking station is indicated by attribute ~at~, e.g. #+BEGIN_SRC prolog - init(object(pickingStation, 1), value(at, (2,3))). + init(object(pickingStation, 1), value(at, (2,3))). #+END_SRC states that pickingStation 1 is at location (2,3). @@ -836,28 +880,28 @@ - The grid position of a charging station is indicated by attribute ~at~, e.g. #+BEGIN_SRC prolog - init(object(chargingStation, 1), value(at, (2,3))). + init(object(chargingStation, 1), value(at, (2,3))). #+END_SRC states that chargingStation 1 is at location (2,3). - The charge rate of a charging station is indicated by attribute ~chargeRate~, e.g. #+BEGIN_SRC prolog - init(object(chargingStation, 1), value(chargeRate, (5,2))). + init(object(chargingStation, 1), value(chargeRate, (5,2))). #+END_SRC states that chargingStation 1 charges 5 battery levels in 2 time steps. **** Example #+BEGIN_SRC prolog - init(object(chargingStation, 1), value(at, (2, 3))). - init(object(chargingStation, 1), value(subtype, 2). - init(object(subtype(charginStation), 2), value(chargeRate, (5, 2)). + init(object(chargingStation, 1), value(at, (2, 3))). + init(object(chargingStation, 1), value(subtype, 2). + init(object(subtype(charginStation), 2), value(chargeRate, (5, 2)). #+END_SRC states that 1) charging station 1 is located at (2,3). 2) charging station 1 is of object-subtype 2. 3) charging stations of object-subtype 2 have a charge rate of 5 battery levels in 2 time - steps. + steps. *** Restocking Station (Introduced by [[#cid:d84e72a4-2202-4331-8636-b56dd264c641][Replenishment]]) @@ -868,7 +912,7 @@ - The grid position of a restocking station is indicated by attribute ~at~, e.g. #+BEGIN_SRC prolog - init(object(restockingStation, 1), value(at, (2,3))). + init(object(restockingStation, 1), value(at, (2,3))). #+END_SRC states that restockingStation 1 is at location (2,3). @@ -888,8 +932,8 @@ + ~move~ * tells the robot to move in a cardinal direction to an adjacent grid node * takes a binary ~~ tuple with the domain ~(-1,0), (1,0), (0,-1), (0,1)~ that - indicates the four possible movement directions 'West, East, South, North' in relation to - the robot's current location + indicates the four possible movement directions 'West, East, South, North' in relation to + the robot's current location + ~pickup~ * tells the robot to pick up the shelf at its current location * takes an empty ~~ tuple @@ -898,18 +942,18 @@ * takes an empty ~~ tuple + ~deliver~ * for the [[#cid:b0f981f8-3202-42c0-a46e-aa6f1a52629b][default domain]] (i.e. plans that consider product quantities): - + tells the robot to deliver a certain amount of units of a product to (partially) fill a specific order - + is only applicable if robot is at a picking station - + takes as ~~ a triple comprised by - 1. the object ID of the order - 2. the object ID by the Product - 3. the number of product units + + tells the robot to deliver a certain amount of units of a product to (partially) fill a specific order + + is only applicable if robot is at a picking station + + takes as ~~ a triple comprised by + 1. the object ID of the order + 2. the object ID by the Product + 3. the number of product units * in case [[#cid:49448523-5e9b-4ed2-ac1a-6754d838b85c][product quantities are ignored]]: - + tells the robot to deliver a product to fill a specific order - + is only applicable if robot is at a picking station - + takes as ~~ a tuple comprised by - 1. the object ID of the order - 2. the object ID by the Product + + tells the robot to deliver a product to fill a specific order + + is only applicable if robot is at a picking station + + takes as ~~ a tuple comprised by + 1. the object ID of the order + 2. the object ID by the Product - ~