contrib/gdl-benchmark/run-temperance.ros @ 45622a0c4e96
Set up the basic framework for the benchmark
| author | Steve Losh <steve@stevelosh.com> |
|---|---|
| date | Wed, 24 Aug 2016 15:43:20 +0000 |
| parents | 9da17791e5da |
| children | 1f0a36161f17 |
#!/bin/sh #|-*- mode:lisp -*-|# #| exec ros -Q -- $0 "$@" |# ;;;; Dependencies ------------------------------------------------------------- (ql:quickload :uiop :silent t) (ql:quickload :unix-opts :silent t) (ql:quickload :split-sequence :silent t) (ql:quickload :losh :silent t) (ql:quickload :temperance :silent t) ;;;; Package ------------------------------------------------------------------ (defpackage #:temperance.contrib.gdl-benchmark (:use #:cl #:cl-arrows #:losh #:temperance.quickutils #:temperance)) (in-package #:temperance.contrib.gdl-benchmark) ;;;; Benchmarking ------------------------------------------------------------- (defun read-file (path) (with-open-file (file path :direction :input) (loop :for form = (read file nil 'eof) :until (eq form 'eof) :collect form))) (defun read-gdl (path) (read-file path)) (defun read-trace (path) ;; (moves m1 m2 ...) -> (m1 m2 ...) (mapcar #'rest (read-file path))) (defun load-gdl-preamble () (push-logic-frame-with t (rule t (not ?x) (call ?x) ! fail) (fact t (not ?x)) (rule t (or ?x ?y) (call ?x)) (rule t (or ?x ?y) (call ?y)) (rule t (distinct ?x ?x) ! fail) (fact t (distinct ?x ?y)))) (defun build-clause (clause) (if (and (consp clause) (eq (first clause) '<=)) (destructuring-bind (arrow head . body) clause (declare (ignore arrow)) (apply #'invoke-rule t head body)) (invoke-fact t clause))) (defun build-database (gdl) (reset-standard-database) (load-gdl-preamble) (push-logic-frame-with t (mapc #'build-clause gdl))) (defun normalize-state (state) ;; TODO: should this be excluded from the benchmark? (remove-duplicates state :test 'equal)) (defun initial-state () (normalize-state (query-map t (lambda (r) (getf r '?what)) (init ?what)))) (defun terminalp () (prove t terminal)) (defun roles () (query-map t (lambda (r) (getf r '?role)) (role ?role))) (defun goal-values () (remove-duplicates (query-all t (goal ?role ?goal)) :test 'equal)) (defun next-state () (normalize-state (query-map t (lambda (r) (getf r '?what)) (next ?what)))) (defun apply-state (state) (push-logic-frame-with t (loop :for fact :in state :do (invoke-fact t `(true ,fact))))) (defun apply-moves (moves) (push-logic-frame-with t (loop :for (role . action) :in moves :do (invoke-fact t `(does ,role ,action))))) (defun clear-state () (pop-logic-frame t)) (defun clear-moves () (pop-logic-frame t)) (defun move= (move1 move2) (equal move1 move2)) (defun move-role= (move1 move2) (eq (car move1) (car move2))) (defun legal-moves () (let* ((individual-moves (remove-duplicates (query-map t (lambda (move) (cons (getf move '?role) (getf move '?action))) (legal ?role ?action)) :test #'move=)) (player-moves (equivalence-classes #'move-role= individual-moves)) (joint-moves (apply #'map-product #'list player-moves))) joint-moves)) (defun build-traces (traces) (loop :with roles = (roles) ;; ugly to depend on the logic here but whatever idc :for trace :in traces :collect (loop :for move :in trace :for role :in roles :collect (cons role move)))) (defun run (modes limit gdl-file trace-file) (declare (ignore modes limit)) (build-database (read-gdl gdl-file)) (build-traces ()) (print (roles)) (print (build-traces (read-trace trace-file))) (print (initial-state)) (print (terminalp)) (apply-state (initial-state)) (print (legal-moves)) ) ;;;; CLI ---------------------------------------------------------------------- (defun program-name () ;; dammit roswell (let ((ros-opts (uiop:getenv "ROS_OPTS"))) (if ros-opts (read-from-string (second (assoc "script" (let ((*read-eval*)) (read-from-string ros-opts)) :test 'equal))) (first (opts:argv))))) (opts:define-opts (:name :help :description "print this help text" :short #\h :long "help") (:name :verbose :description "verbose output" :short #\v :long "verbose")) (defparameter *required-options* (format nil "Required parameters: SEARCH-MODES A space-separated list of one or more of {dfs, fdfs, mc}. LIMIT A positive integer denoting the playclock limit (for dfs/mc) or depth limit (for fdfs). GDL-FILE Path to the GDL file to run. Does NOT need the version with the extra base propositions. TRACE-FILE Path to the corresponding trace file.")) (defparameter *verbose* nil) (defun usage () (let ((prog (program-name))) (opts:describe :prefix (format nil "~A - Benchmark Temperance for GDL reasoning." prog) :suffix *required-options* :usage-of prog :args "SEARCH-MODES LIMIT GDL-FILE TRACE-FILE"))) (defun die (message &rest args) (terpri) (apply #'format *error-output* message args) #+sbcl (sb-ext:exit :code 1) #-sbcl (quit)) (defun parse-modes (modes) (-<> modes (split-sequence:split-sequence #\space <> :remove-empty-subseqs t) (mapcar #'string-upcase <>) (mapcar #'ensure-keyword <>))) (defun parse-limit (limit) (handler-case (parse-integer limit) (parse-error (e) (declare (ignore e)) (die "ERROR: limit '~A' is not an integer.~%" limit)))) (defun main (&rest argv) (multiple-value-bind (options arguments) (opts:get-opts argv) (setf *verbose* (getf options :verbose)) (when (getf options :help) (usage) (return-from main)) (when (not (= 4 (length arguments))) (usage) (die "ERROR: All arguments are required.~%")) (destructuring-bind (modes limit gdl-file trace-file) arguments (run (parse-modes modes) (parse-limit limit) gdl-file trace-file))))