PDDL temporal modelling help: how to change numeric value in the background? - planning

I'm trying to model and RTS game (AOE2) for an optimal build order and plan using OPTIC. My thought is to represent villagers (workers) as a function, then resources increase depending on the number of villagers. This action works, but I believe is inefficient and the plans are not optimal:
(:durative-action collect_resource
:parameters (?r - resource) ;wood, food etc.
:duration (= ?duration 10)
:condition (and
(at start (> (workers ?r) 0))
(at start (idle ?r))
)
:effect (and
(at start (not (idle ?r)))
(at start (working ?r))
(at end (idle ?r))
(at end (not (working ?r)))
(at end (increase (amount ?r) (* (collect_rate ?r)(workers ?r))))
)
)
I tried this PDDL Durative-Action: Flexible duration, but OPTIC doesn't support non-linear numeric conditions:
(increase (amount ?r) (* (#t)(* (collect_rate ?r)(workers ?r)))
Does anyone have any suggestions for a better approach?
EDIT (error message):
Unfortunately, the planner does not supported non-linear numeric conditions,
effects, or duration constraints, but one or more of these is present in
the problem you have provided. Specifically, the sub-expression:
(3*(workers lumber1)) * (#t)
... was encountered. To use this planner with your problem, you will have
to reformulate it to avoid these.
Domain:
(define (domain aoe2)
(:requirements :strips :typing :fluents :durative-actions :timed-initial-literals)
(:types
location society - object
resource building - location
town_center barracks - building
lumber berries sheep gold - resource
)
(:predicates
(working ?l - location)
(idle ?l - location)
)
(:functions
(idle_villagers ?s - society)
(train_villager_time ?s - society)
(workers ?r - resource)
(walk_time ?r - resource)
(collect_rate ?r - resource)
(amount ?r - resource)
)
(:durative-action train_villager
:parameters (?tc - town_center ?s - society)
:duration (= ?duration (train_villager_time ?s))
:condition (and
(at start (idle ?tc))
)
:effect (and
(at start (not (idle ?tc)))
(at start (working ?tc))
(at end (idle ?tc))
(at end (not (working ?tc)))
(at end (increase (idle_villagers ?s) 1))
)
)
(:durative-action send_idle_to_resource
:parameters (?r - resource ?s - society)
:duration (= ?duration (walk_time ?r))
:condition (and
(at start (> (idle_villagers ?s) 0))
)
:effect (and
(at start (decrease (idle_villagers ?s) 1))
(at end (increase (workers ?r) 1))
)
)
(:action send_resource_to_idle
:parameters (?r - resource ?s - society)
:precondition (and
(> (workers ?r) 0)
)
:effect (and
(increase (idle_villagers ?s) 1)
(decrease (workers ?r) 1)
)
)
(:durative-action collect_resource
:parameters (?r - resource)
:duration (= ?duration 10)
:condition (and
(at start (> (workers ?r) 0))
(at start (idle ?r))
)
:effect (and
(at start (not (idle ?r)))
(at start (working ?r))
(at end (idle ?r))
(at end (not (working ?r)))
(at end (increase (amount ?r) (* (collect_rate ?r)(workers ?r))))
)
)
)
Problem
(define (problem dark_age)
(:domain aoe2)
(:requirements :strips :typing :fluents :durative-actions :timed-initial-literals)
(:objects
tc1 - town_center
mysociety - society
lumber1 - lumber
sheep1 - sheep
)
(:init
(= (train_villager_time mysociety) 25)
(= (idle_villagers mysociety) 0)
(idle tc1)
(= (workers lumber1) 0)
(= (walk_time lumber1) 5)
(= (collect_rate lumber1) 3)
(= (amount lumber1) 0)
(idle lumber1)
(= (workers sheep1) 5)
(= (walk_time sheep1) 0)
(= (collect_rate sheep1) 3)
(= (amount sheep1) 0)
(idle sheep1)
)
(:goal
(and
; (= (idle_villagers mysociety) 1)
; (> (workers lumber1) 1)
(> (amount lumber1) 600)
(> (amount sheep1) 600)
)
)
)

Related

How to access sub-struct variables in Racket (Lisp/Scheme)

I'm trying to write an AM/PM clock conversion function to a 24 hour clock (military time), but there's a struct and sub-struct that have variables I can't figure out how to pull. Neither 24HourClock-hours or AM/PM-hours is working to pull the hours or minutes variable out of the AM/PM instance of time that goes as the parameter of each of the two versions of the function.
The following two functions are two separate attempts at the same function:
(define (AM/PM->24HourClock2 time)
(cond
[(isAM? time) (24HourClock (24HourClock-hours 24HourClock-minutes))]
[else (24HourClock (+ 24HourClock-hours 12) 24HourClock-minutes)]))
(define (AM/PM->24HourClock time)
(cond
[(isAM? time) (24HourClock (AM/PM-hours AM/PM-minutes))]
[else (24HourClock (+ AM/PM-hours 12) AM/PM-minutes)]))
This one attempts to use a lambda function to access the sub-members:
(define (AM/PM->24HourClock time)
(lambda (hr min meridiem)
(cond
[(isAM? time) (24HourClock (hr min))]
[else (24HourClock (+ hr 12) min)]))
But here's the output:
Here's the earlier code that makes it reproducible:
#lang slideshow
(struct 24HourClock (hours minutes)
#:transparent
#:mutable
#:guard (lambda (hours minutes err_name)
(if (not (and (>= hours 0) (< hours 24)))
(error err_name "Hours must be between 0 and 24")
(if (not (and (>= minutes 0) (< minutes 60)))
(error err_name "Minutes must be between 0 and 60")
(values hours minutes)))))
(struct AM/PM 24HourClock (meridiem)
#:transparent
#:mutable
#:guard (lambda (hours minutes meridiem err_name)
(if (not(and(and(number? hours)(> hours 0)(<= hours 12)(number? minutes))))
(error err_name "Hours must be between 1 and 12 : 0")
(if [not (and(string? meridiem)(or
(equal? meridiem "am")
(equal? meridiem "AM")
(equal? meridiem "pm")
(equal? meridiem "PM")))]
(error err_name "Invalid value for meridiem")
(values hours minutes meridiem)))))
(define (isAM? time)
(or (equal? (AM/PM-meridiem time) "AM")
(equal? (AM/PM-meridiem time) "am")))
It should be rather
(define (AM/PM->24HourClock2 time)
(cond
[(isAM? time) (24HourClock (AM/PM-hours time) (AM/PM-minutes time))]
[else (24HourClock (+ (AM/PM-hours time) 12) (AM/PM-minutes time))]))
(define (AM/PM->24HourClock time)
(let ((hr (AM/PM-hours time))
(min (AM/PM-minutes time))
(mer (AM/PM-meridiem time)))
(cond
[(isAM? time) (24HourClock hr min)]
[else (24HourClock (+ hr 12) min)])))
But since AM/PM-hours and AM/PM-minutes are not defined when defining like you did here with 24HourClock as super class, you have to write:
(define (AM/PM->24HourClock2 time)
(cond
[(isAM? time) (24HourClock (24HourClock-hours time) (24HourClock-minutes time))]
[else (24HourClock (+ (24HourClock-hours time) 12) (24HourClock-minutes time))]))
(define (AM/PM->24HourClock time)
(let ((hr (24HourClock-hours time))
(min (24HourClock-minutes time))
(mer (AM/PM-meridiem time)))
(cond
[(isAM? time) (24HourClock hr min)]
[else (24HourClock (+ hr 12) min)])))
Your problem is that you think struct-slot is itself the value of slot in struct. But it isn't. It is just the getter function for the slot in struct. Therefore, you have to do (struct-slot instance) to get the value of slot in the instance which is of the type struct.
If you want AM/PM->24HourClock, then time is of the type AM/PM.
This is all code put together, it's the same as your response and what was shown:
#lang slideshow
(struct 24HourClock (hours minutes) #:transparent #:mutable
#:guard (lambda (hours minutes err_name)
(if (not (and (>= hours 0) (< hours 24)))
(error err_name "Hours must be between 0 and 24")
(if (not (and (>= minutes 0) (< minutes 60)))
(error err_name "Minutes must be between 0 and 60")
(values hours minutes)))))
(struct AM/PM 24HourClock (meridiem) #:transparent #:mutable
#:guard (lambda (hours minutes meridiem err_name)
(if (not(and(and(number? hours)(> hours 0)(<= hours 12)(number? minutes))))
(error err_name "Hours must be between 1 and 12 : 0")
(if [not (and(string? meridiem)(or
(equal? meridiem "am")
(equal? meridiem "AM")
(equal? meridiem "pm")
(equal? meridiem "PM")))]
(error err_name "Invalid value for meridiem")
(values hours minutes meridiem)))))
(define (isAM? time)
(or (equal? (AM/PM-meridiem time) "AM")
(equal? (AM/PM-meridiem time) "am")))
(define (AM/PM->24HourClock time)
(let ((hr (AM/PM-hours time))
(min (AM/PM-minutes time))
(cond
[(isAM? time) (24HourClock hr min)]
[else (24HourClock (+ hr 12) min)])))
Here's what I use for test cases:
;=======================
; Test Cases
;=======================
; (24HourClock 0 20)
; (24HourClock 24 20)
; (24HourClock 11 60)
; (AM/PM 0 20 "AM")
; (AM/PM 1 20 "Am")
; (AM/PM 2 20 "am")
; (is-AM? 2 20 "am")
; (AM/PM->24HourClock (AM/PM 0 10 "AM"))
; (AM/PM->24HourClock (AM/PM 12 10 "am"))

minimize in metric pddl

I created the pddl domain for the figure here
However, when trying to reach the node number 7 the output of the Metric-ff planner is cost = 21 insted of 15
also for the node 5 the cost = 16 insted of 10
it seems it minimizes the number of steps insted of the cost
can some one help?
(define (problem petriproblem)
(:domain petri)
(:objects
token - token
spring summer fall winter - place
)
(:init
(at token spring)
(= (initial-token token) 3)
(connected token spring summer)
(connected token summer fall)
(connected token fall winter)
(connected token winter spring)
(= (required-token spring summer) 1)
(= (required-token summer fall) 1)
(= (required-token fall winter) 1)
(= (total-tokens-used) 0) )
(:goal
(at token winter)
)
(:metric minimize
(total-tokens-used)
)
)
------------------------------------------------------------------------
(define (problem nodes)
(:domain petri)
(:objects
token - token
node1 node2 node3 node4 node5 node6 node7 - place
)
(:init
(at token node1)
(= (initial-token token) 1000)
(connected token node1 node2)
(connected token node2 node4)
(connected token node3 node5)
(connected token node4 node3)
(connected token node4 node5)
(connected token node4 node6)
(connected token node4 node7)
(connected token node6 node7)
(= (required-token node1 node2) 2)
(= (required-token node2 node4) 4)
(= (required-token node3 node5) 2)
(= (required-token node4 node3) 2)
(= (required-token node4 node5) 10)
(= (required-token node4 node6) 4)
(= (required-token node4 node7) 15)
(= (required-token node6 node7) 5)
(= (total-tokens-used) 0)
)
(:goal
(at token node5)
)
(:metric minimize
(total-tokens-used)
)
)

Not overwriting *standard-input* prevents multi-threading

I have a Common Lisp program that behaves differently depending on how I use *standard-input*. Here are the details:
(if input-stream?
(process)
(with-open-file (*standard-input* up :element-type 'unsigned-byte)
(process)))
The process function starts multiple threads. Each thread reads part of the standard input, writes it in a file (all within a lock) and processes the resulting files in parallel (out of the lock). In fact it processes the resulting files in parallel only in case input-stream? is false otherwise it processes them sequentially.
(defun process ()
(let ((psize 4194304)
(stream *standard-input*)
(result-lock (bt:make-lock))
(input-stream-lock (bt:make-lock))
eof)
(flet ((add-job (fname)
(make-thread
#'(lambda ()
(do () (eof)
(when (bt:with-lock-held (input-stream-lock)
(unless eof
(setq eof (write-input-stream-to-file stream fname psize))
t))
(sleep 0.1)
(bt:with-lock-held (result-lock)
(display-progress))))))))
(mapcar
#'join-thread
(loop for i from 1 to 10
collect (add-job
(make-pathname :directory "/tmp"
:name "test"
:type (princ-to-string i))))))))
(let ((counter 0))
(defun display-progress ()
(if (zerop (mod (incf counter) 10))
(format t " ~a " counter)
(write-char #\+))))
(defun write-input-stream-to-file (stream fname psize-bytes)
(with-open-file (out fname
:direction :output
:element-type 'unsigned-byte
:if-exists :supersede)
(do ((byte (read-byte stream nil nil)
(read-byte stream nil nil))
(offset 0 (1+ offset)))
((or (= offset psize-bytes) (null byte)) (not byte))
(write-byte byte out))))
If we create a FIFO (with mkfifo), copy the file to it and run the program with it instead, we again observe parallelism.
The above program is built as a command line utility with ECL and runs on Linux. I run it in one of the following ways:
cat "bigfile" | my-program
my-program "bigfile"
Parallelism happens only in case 2.
The question is why the difference?
Update:
I had mistake in my question. Now it is OK.
Added the process function and described how I run the program

compilation unit aborted, caught 1 fatal ERROR condition?

I have some common lisp code that is behaving oddly. It's a TCP client/server application.
Unless I add (sleep 0.01) or similar at the end of my code, I get the following utterly unhelpful error message after my program completes. It is a very short-lived program, simply hosting a TCP server and testing that it can be connected to.
;; compilation unit aborted; caught 1 fatal ERROR condition
This doesn't happen every time, maybe 80% of the runs cause this. There is no context, no explanation.
Code to reproduce the problem:
(defmacro with-gensyms ((&rest names) &body body)
`(let ,(loop for n in names collect `(,n (gensym)))
,#body))
(defmacro kilobytes (qty)
(* qty 1024))
(defun is-sequence (sequence)
(or (listp sequence) (vectorp sequence)))
(defmacro append-to (seq values)
(with-gensyms (cached-values)
`(let ((,cached-values ,values))
(cond
((is-sequence ,cached-values)
(setf ,seq (append ,seq (coerce ,cached-values 'list))))
(t
(setf ,seq (append ,seq (list ,cached-values))))))))
(defmacro remove-from (seq value)
(with-gensyms (cached-value)
`(let ((,cached-value ,value))
(delete-if (lambda (value) (equalp value ,cached-value)) ,seq))))
(defclass tcp-server ()
((server-socket :initform nil)
(server-threads :initform (list))))
(defgeneric start-server (this &key port bind-address buffer-length))
(defmethod start-server ((this tcp-server) &key (port 0) (bind-address #(127 0 0 1)) (buffer-length (kilobytes 10)))
(with-slots (server-socket server-threads) this
(when server-socket
(error "Server already running"))
(let ((backlog 5))
(setf server-socket (make-instance 'sb-bsd-sockets:inet-socket :type :stream :protocol :tcp))
(sb-bsd-sockets:socket-bind server-socket bind-address port)
(sb-bsd-sockets:socket-listen server-socket backlog)
(flet ((handle-connection (client-socket)
(let ((buffer (make-array buffer-length :element-type '(unsigned-byte 8) :fill-pointer t)))
(catch 'eof
(loop
while (sb-bsd-sockets:socket-open-p client-socket)
do (let ((length (nth-value 1 (sb-bsd-sockets:socket-receive client-socket buffer nil))))
(when (eq 0 length)
(throw 'eof nil)))))
(sb-bsd-sockets::socket-close client-socket)
(remove-from server-threads sb-thread:*current-thread*))))
(sb-thread:make-thread
(lambda ()
(loop
while (and server-socket (sb-bsd-sockets:socket-open-p server-socket))
do
(let ((client-socket (sb-bsd-sockets:socket-accept server-socket))) ;; Listen for incoming connections
(append-to server-threads
(sb-thread:make-thread #'handle-connection :name "Connection handler" :arguments client-socket)))) ;; Spawn a process to handle the connection))
(remove-from server-threads sb-thread:*current-thread*))
:name "Server")))
nil))
(defun start-tcp-server (&key (port 0) (bind-address #(127 0 0 1)) (buffer-length (kilobytes 10)))
(let ((server (make-instance 'tcp-server)))
(start-server server :port port :bind-address bind-address :buffer-length buffer-length)
server))
(defgeneric stop-server (this))
(defmethod stop-server ((this tcp-server))
(with-slots (server-socket server-threads) this
(unless server-socket
(error "Server not running"))
(sb-bsd-sockets:socket-close server-socket)
(setf server-socket nil)
(loop for thread in (reverse server-threads)
; do (sb-thread:interrupt-thread thread 'sb-thread:abort-thread))
do (sb-thread:terminate-thread thread))
(loop for thread in (reverse server-threads)
do (sb-thread:join-thread thread :default nil))))
(defgeneric server-running? (this))
(defmethod server-running? ((this tcp-server))
(if (slot-value this 'server-socket) t nil))
(defgeneric server-port (this))
(defmethod server-port ((this tcp-server))
(nth-value 1 (sb-bsd-sockets:socket-name (slot-value this 'server-socket))))
(let ((server-instance nil))
(defun deltabackup-start-server (&key (port 0) (bind-address #(127 0 0 1)) (buffer-length (kilobytes 10)))
(setf server-instance (start-tcp-server :port port
:bind-address bind-address
:buffer-length buffer-length))
nil)
(defun deltabackup-stop-server ()
(unless server-instance
(error "Server not running"))
(stop-server server-instance)
(setf server-instance nil))
(defun deltabackup-server-running? ()
(server-running? server-instance))
(defun deltabackup-server-port ()
(server-port server-instance)))
(defmacro with-tcp-client-connection (address port socket-var &body body-forms)
(with-gensyms (client-socket)
`(let* ((,client-socket (make-instance 'sb-bsd-sockets:inet-socket :type :stream :protocol :tcp))
(,socket-var ,client-socket)) ; duplicate this, to prevent body-form modifying the original
(sb-bsd-sockets:socket-connect ,client-socket ,address ,port)
(unless ,client-socket
(error "Failed to connect"))
,#body-forms
(sb-bsd-sockets:socket-close ,client-socket))))
(defmacro with-running-server ( (&optional (port 0)) &body body-forms)
`(progn
(deltabackup-start-server :port ,port)
(unless (deltabackup-server-running?)
(error "Server did not run"))
,#body-forms
(deltabackup-stop-server)))
(with-running-server ()
(with-tcp-client-connection #(127 0 0 1) (deltabackup-server-port) client-socket
client-socket))
Using SBCL common lisp.
The reason you get such a vague error message is that you're running directly from the command line and the error is happening in a thread. If you can get the error to happen in EMACS under SLIME, you'll get more detailed error information.
I ran your program from SLIME like this:
CL-USER> (loop repeat 100 do (load "/tmp/stackoverflow.lisp"))
...and got the following error in SLIME:
Socket error in "accept": EBADF (Bad file descriptor)
[Condition of type SB-BSD-SOCKETS:BAD-FILE-DESCRIPTOR-ERROR]
So, something is going wrong on the server's end when you try to accept the connection. My theory is you have a race condition. In the server thread, you have this:
(loop
while (and server-socket (sb-bsd-sockets:socket-open-p server-socket))
do
(let ((client-socket (sb-bsd-sockets:socket-accept server-socket))) ;; Listen for incoming connections
....))
...and in the client thread, you do this:
(defmethod stop-server ((this tcp-server))
(with-slots (server-socket server-threads) this
(unless server-socket
(error "Server not running"))
(sb-bsd-sockets:socket-close server-socket)
It is possible for sb-bsd-sockets:socket-close to be called and to finish between the call to socket-open-p and socket-accept in the server thread, so that socket-accept gets called on a closed socket.

Lisp Toolkit (ltk): Cannot get SCALE :variable value

I am working with SBCL for Linux on an AMD64 machine.
Function CONTROL-TEST makes a window with a drawing CANVAS and two sliding SCALEs. The slider :VARIABLES for UPPER-SLIDER and FORE-SLIDER are supposed to be bound to UPPER-THETA and FORE-THETA, respectively, but the update code never sees anything but 0. I have tested the update code in another function.
(defun controltest ()
"Test of a user-controlled robot arm"
(with-ltk ()
; (make-instance 'scale :master fscale :from 0 :to 100 :length 150 )
(let* ((upper-theta 0) (fore-theta 0)
(upper-slider
(make-instance 'scale :from 0 :to 7
:length 360 :variable upper-theta))
(fore-slider
(make-instance 'scale :from 0 :to 7
:length 360 :variable fore-theta))
(cnvs (make-instance 'canvas :width cnvs-width :height cnvs-height))
(upper (manip:uctk-beam :cen-x 200 :cen-y 200
:b-length 40 :b-width 20
:tk-cnvs cnvs))
(fore (manip:uctk-beam :cen-x 0 :cen-y 40 ; relative to upper
:b-length 40 :b-width 20
:tk-cnvs cnvs))
(slp-time 50))
(labels ((update ()
(draw upper nil) ; contains FORE, no need to draw separately
(geo:set-member-theta upper 2 fore-theta)
(geo:set-theta upper upper-theta)
(after slp-time #'update)))
(geo:add-geo upper fore) ; make FORE a member of UPPER
(pack cnvs :fill :both :expand 1)
(pack upper-slider :side :bottom)
(pack fore-slider :side :bottom)
(update)))))
Please excuse me, it appears I did not perform my due diligence, this question
was answered 3 years ago at the following location:
http://permalink.gmane.org/gmane.lisp.ltk.user/329
The answer is that the name passed to :VARIABLE is not in fact updated
automatically. Instead of messing with :VARIABLE, I pass a LAMBDA expression to
the :COMMAND keyword; and therefore the following is the correct way:
(upper-slider
(make-instance 'scale :from 0 :to 7
:length 360
:command (lambda (val) (setq upper-theta val))))
(fore-slider
(make-instance 'scale :from 0 :to 7
:length 360
:command (lambda (val) (setq fore-theta val))))

Resources