garaemon.net: 脳汁でコードを書く
menu
recent-articles
rosinstall
今日は意外と要望があるかもしれないと思って, rosinstallについて書きます.
rosinstallとはROS とよばれるロボットミドルウェアの環境構築において, はじめに 利用するスクリプトです. 参考
ROSは, aptでのインストールもサポートしていますが, 個人的にはソースコードから buildするのを好んで使っています.
このページ によると, 例えば以下のような例があげられていますが,
$ rosinstall ~/ros http://ros.org/rosinstalls/cturtle_ros.rosinstall
この*.rosinstallというファイルは自分で書いても良いので, 自分なりのrosinstallファイルを 書くことをおすすめします(ROS初心者は意外とこれに気づいていないかも).
たとえば, 以下のようなgaraemon.rosinstallを用意してみます.
$ cat garaemon.rosinstall
- svn:
uri: https://code.ros.org/svn/ros/stacks/ros/tags/cturtle
local-name: ros
- svn:
uri: https://code.ros.org/svn/wg-ros-pkg/stacks/arm_navigation/tags/cturtle
local-name: stacks/arm_navigation
- svn:
uri: https://code.ros.org/svn/ros-pkg/stacks/camera_drivers/tags/cturtle
local-name: stacks/camera_drivers
- svn:
uri: https://code.ros.org/svn/wg-ros-pkg/stacks/collision_environment/tags/cturtle
local-name: stacks/collision_environment
- svn:
uri: https://code.ros.org/svn/ros-pkg/stacks/common/tags/cturtle
local-name: stacks/common
- svn:
uri: https://code.ros.org/svn/ros-pkg/stacks/common_msgs/tags/cturtle
local-name: stacks/common_msgs
- svn:
uri: https://code.ros.org/svn/ros-pkg/stacks/diagnostics/tags/cturtle
local-name: stacks/diagnostics
- svn:
uri: https://code.ros.org/svn/ros-pkg/stacks/driver_common/tags/cturtle
local-name: stacks/driver_common
- svn:
uri: https://code.ros.org/svn/wg-ros-pkg/stacks/executive_python/tags/cturtle
local-name: stacks/executive_python
- svn:
uri: https://code.ros.org/svn/ros-pkg/stacks/executive_smach/tags/cturtle
local-name: stacks/executive_smach
- svn:
uri: https://code.ros.org/svn/ros-pkg/stacks/geometry/tags/cturtle
local-name: stacks/geometry
- svn:
uri: https://code.ros.org/svn/ros-pkg/stacks/graph_mapping/tags/cturtle
local-name: stacks/graph_mapping
- svn:
uri: https://code.ros.org/svn/ros-pkg/stacks/image_common/tags/cturtle
local-name: stacks/image_common
- svn:
uri: https://code.ros.org/svn/ros-pkg/stacks/image_pipeline/tags/cturtle
local-name: stacks/image_pipeline
- svn:
uri: https://code.ros.org/svn/ros-pkg/stacks/image_transport_plugins/tags/cturtle
local-name: stacks/image_transport_plugins
- svn:
uri: https://code.ros.org/svn/ros-pkg/stacks/imu_drivers/tags/cturtle
local-name: stacks/imu_drivers
- svn:
uri: https://code.ros.org/svn/ros-pkg/stacks/joystick_drivers/tags/cturtle
local-name: stacks/joystick_drivers
- svn:
uri: https://code.ros.org/svn/ros-pkg/stacks/joystick_drivers_tutorials/tags/cturtle
local-name: stacks/joystick_drivers_tutorials
- svn:
uri: https://code.ros.org/svn/wg-ros-pkg/stacks/kinematics/tags/cturtle
local-name: stacks/kinematics
- svn:
uri: https://code.ros.org/svn/ros-pkg/stacks/laser_drivers/tags/cturtle
local-name: stacks/laser_drivers
- svn:
uri: https://code.ros.org/svn/ros-pkg/stacks/laser_pipeline/tags/cturtle
local-name: stacks/laser_pipeline
- svn:
uri: https://code.ros.org/svn/wg-ros-pkg/stacks/motion_planners/tags/cturtle
local-name: stacks/motion_planners
- svn:
uri: https://code.ros.org/svn/wg-ros-pkg/stacks/motion_planning_common/tags/cturtle
local-name: stacks/motion_planning_common
- svn:
uri: https://code.ros.org/svn/wg-ros-pkg/stacks/motion_planning_environment/tags/cturtle
local-name: stacks/motion_planning_environment
- svn:
uri: https://code.ros.org/svn/wg-ros-pkg/stacks/motion_planning_visualization/tags/cturtle
local-name: stacks/motion_planning_visualization
- svn:
uri: https://code.ros.org/svn/ros-pkg/stacks/navigation/tags/cturtle
local-name: stacks/navigation
- svn:
uri: https://code.ros.org/svn/wg-ros-pkg/stacks/object_manipulation/tags/cturtle
local-name: stacks/object_manipulation
- svn:
uri: https://code.ros.org/svn/wg-ros-pkg/stacks/people/tags/cturtle
local-name: stacks/people
- svn:
uri: https://code.ros.org/svn/ros-pkg/stacks/physics_ode/tags/cturtle
local-name: stacks/physics_ode
- svn:
uri: https://code.ros.org/svn/ros-pkg/stacks/point_cloud_perception/tags/cturtle
local-name: stacks/point_cloud_perception
- svn:
uri: https://code.ros.org/svn/wg-ros-pkg/stacks/pr2_apps/tags/cturtle
local-name: stacks/pr2_apps
- svn:
uri: https://code.ros.org/svn/wg-ros-pkg/stacks/pr2_arm_navigation/tags/cturtle
local-name: stacks/pr2_arm_navigation
- svn:
uri: https://code.ros.org/svn/wg-ros-pkg/stacks/pr2_arm_navigation_apps/tags/cturtle
local-name: stacks/pr2_arm_navigation_apps
- svn:
uri: https://code.ros.org/svn/wg-ros-pkg/stacks/pr2_arm_navigation_tests/tags/cturtle
local-name: stacks/pr2_arm_navigation_tests
- svn:
uri: https://code.ros.org/svn/wg-ros-pkg/stacks/pr2_calibration/tags/cturtle
local-name: stacks/pr2_calibration
- svn:
uri: https://code.ros.org/svn/wg-ros-pkg/stacks/pr2_cockpit/tags/cturtle
local-name: stacks/pr2_cockpit
- svn:
uri: https://code.ros.org/svn/wg-ros-pkg/stacks/pr2_common/tags/cturtle
local-name: stacks/pr2_common
- svn:
uri: https://code.ros.org/svn/wg-ros-pkg/stacks/pr2_common_actions/tags/cturtle
local-name: stacks/pr2_common_actions
- svn:
uri: https://code.ros.org/svn/wg-ros-pkg/stacks/pr2_controllers/tags/cturtle
local-name: stacks/pr2_controllers
- svn:
uri: https://code.ros.org/svn/wg-ros-pkg/stacks/pr2_doors/tags/cturtle
local-name: stacks/pr2_doors
- svn:
uri: https://code.ros.org/svn/wg-ros-pkg/stacks/pr2_ethercat_drivers/tags/cturtle
local-name: stacks/pr2_ethercat_drivers
- svn:
uri: https://code.ros.org/svn/wg-ros-pkg/stacks/pr2_gui/tags/cturtle
local-name: stacks/pr2_gui
- svn:
uri: https://code.ros.org/svn/wg-ros-pkg/stacks/pr2_kinematics/tags/cturtle
local-name: stacks/pr2_kinematics
- svn:
uri: https://code.ros.org/svn/wg-ros-pkg/stacks/pr2_kinematics_with_constraints/tags/cturtle
local-name: stacks/pr2_kinematics_with_constraints
- svn:
uri: https://code.ros.org/svn/wg-ros-pkg/stacks/pr2_mechanism/tags/cturtle
local-name: stacks/pr2_mechanism
- svn:
uri: https://code.ros.org/svn/wg-ros-pkg/stacks/pr2_navigation/tags/cturtle
local-name: stacks/pr2_navigation
- svn:
uri: https://code.ros.org/svn/wg-ros-pkg/stacks/pr2_navigation_apps/tags/cturtle
local-name: stacks/pr2_navigation_apps
- svn:
uri: https://code.ros.org/svn/wg-ros-pkg/stacks/pr2_object_manipulation/tags/cturtle
local-name: stacks/pr2_object_manipulation
- svn:
uri: https://code.ros.org/svn/wg-ros-pkg/stacks/pr2_plugs/tags/cturtle
local-name: stacks/pr2_plugs
- svn:
uri: https://code.ros.org/svn/wg-ros-pkg/stacks/pr2_power_drivers/tags/cturtle
local-name: stacks/pr2_power_drivers
- svn:
uri: https://code.ros.org/svn/wg-ros-pkg/stacks/pr2_robot/tags/cturtle
local-name: stacks/pr2_robot
- svn:
uri: https://code.ros.org/svn/wg-ros-pkg/stacks/pr2_self_test/tags/cturtle
local-name: stacks/pr2_self_test
- svn:
uri: https://code.ros.org/svn/wg-ros-pkg/stacks/pr2_simulator/tags/cturtle
local-name: stacks/pr2_simulator
- svn:
uri: https://code.ros.org/svn/wg-ros-pkg/stacks/pr2_tabletop_manipulation_apps/tags/cturtle
local-name: stacks/pr2_tabletop_manipulation_apps
- svn:
uri: https://code.ros.org/svn/wg-ros-pkg/stacks/pr2_web_apps/tags/cturtle
local-name: stacks/pr2_web_apps
- svn:
uri: https://code.ros.org/svn/ros-pkg/stacks/robot_calibration/tags/cturtle
local-name: stacks/robot_calibration
- svn:
uri: https://code.ros.org/svn/ros-pkg/stacks/robot_model/tags/cturtle
local-name: stacks/robot_model
- svn:
uri: https://code.ros.org/svn/ros/stacks/ros_realtime/tags/cturtle
local-name: stacks/ros_realtime
- svn:
uri: https://code.ros.org/svn/ros/stacks/ros_tutorials/tags/cturtle
local-name: stacks/ros_tutorials
- svn:
uri: https://code.ros.org/svn/ros/stacks/roslisp_support/tags/cturtle
local-name: stacks/roslisp_support
- svn:
uri: https://code.ros.org/svn/ros-pkg/stacks/simulator_gazebo/tags/cturtle
local-name: stacks/simulator_gazebo
- svn:
uri: https://code.ros.org/svn/ros-pkg/stacks/simulator_stage/tags/cturtle
local-name: stacks/simulator_stage
- svn:
uri: https://code.ros.org/svn/ros-pkg/stacks/slam_gmapping/tags/cturtle
local-name: stacks/slam_gmapping
- svn:
uri: https://code.ros.org/svn/ros-pkg/stacks/slam_karto/tags/cturtle
local-name: stacks/slam_karto
- svn:
uri: https://code.ros.org/svn/ros-pkg/stacks/sound_drivers/tags/cturtle
local-name: stacks/sound_drivers
- svn:
uri: https://code.ros.org/svn/wg-ros-pkg/stacks/sql_database/tags/cturtle
local-name: stacks/sql_database
- svn:
uri: https://code.ros.org/svn/wg-ros-pkg/stacks/tabletop_object_perception/tags/cturtle
local-name: stacks/tabletop_object_perception
- svn:
uri: https://code.ros.org/svn/wg-ros-pkg/stacks/trajectory_filters/tags/cturtle
local-name: stacks/trajectory_filters
- svn:
uri: https://code.ros.org/svn/ros-pkg/stacks/vision_opencv/tags/cturtle
local-name: stacks/vision_opencv
- svn:
uri: https://code.ros.org/svn/ros-pkg/stacks/visualization/tags/cturtle
local-name: stacks/visualization
- svn:
uri: https://code.ros.org/svn/ros-pkg/stacks/visualization_common/tags/cturtle
local-name: stacks/visualization_common
- svn:
uri: https://code.ros.org/svn/ros-pkg/stacks/visualization_tutorials/tags/cturtle
local-name: stacks/visualization_tutorials
- svn:
uri: https://code.ros.org/svn/ros-pkg/stacks/vslam/tags/cturtle
local-name: stacks/vslam
- svn:
uri: https://code.ros.org/svn/wg-ros-pkg/stacks/web_interface/tags/cturtle
local-name: stacks/web_interface
- svn:
uri: https://code.ros.org/svn/wg-ros-pkg/stacks/wg_common/tags/cturtle
local-name: stacks/wg_common
- svn:
uri: https://code.ros.org/svn/wg-ros-pkg/stacks/wg_hardware_test/tags/cturtle
local-name: stacks/wg_hardware_test
- svn:
uri: https://code.ros.org/svn/wg-ros-pkg/stacks/wg_pr2_apps/tags/cturtle
local-name: stacks/wg_pr2_apps
- svn:
uri: https://code.ros.org/svn/wg-ros-pkg/stacks/wifi_drivers/tags/cturtle
local-name: stacks/wifi_drivers
- svn:
uri: https://code.ros.org/svn/ros-pkg/stacks/vision_opencv/trunk
local-name: stacks/vision_opencv
- svn:
uri: https://code.ros.org/svn/ros-pkg/branches/trunk_cturtle/stacks/camera_drivers_experimental
local-name: stacks/camera_drivers_experimental
- svn:
uri: https://code.ros.org/svn/wg-ros-pkg/stacks/texas_drivers/tags/latest
local-name: stacks/texas_drivers
- svn:
uri: https://code.ros.org/svn/ros-pkg/stacks/navigation_experimental/tags/cturtle
local-name: stacks/navigation_experimental
- svn:
uri: https://code.ros.org/svn/wg-ros-pkg/stacks/topological_navigation/tags/cturtle
local-name: stacks/topological_navigation
- svn:
uri: https://code.ros.org/svn/wg-ros-pkg/branches/trunk_cturtle
local-name: wg-ros-pkg-unreleased
- svn:
uri: https://code.ros.org/svn/ros-pkg/branches/trunk_cturtle
local-name: ros-pkg-unreleased
- svn:
uri: https://code.ros.org/svn/ros/stacks/ros_experimental/trunk
local-name: ros-experimental-trunk
- svn:
uri: https://cmu-ros-pkg.svn.sourceforge.net/svnroot/cmu-ros-pkg/trunk
local-name: cmu-ros-pkg
- svn:
uri: https://code.ros.org/svn/ros/stacks/ros_tutorials/trunk
local-name: ros_tutorials
- svn:
uri: https://code.ros.org/svn/ros-pkg/branches/trunk_cturtle/stacks/ros_pkg_tutorials
local-name: ros_pkg_tutorials
- svn:
uri: https://ua-ros-pkg.googlecode.com/svn/trunk/arrg
local-name: ua-ros-pkg
- svn:
uri: https://bosch-ros-pkg.svn.sourceforge.net/svnroot/bosch-ros-pkg/trunk
local-name: bosch-ros-pkg
- svn:
uri: https://prairiedog.googlecode.com/svn/trunk
local-name: prairiedog-ros-pkg
- svn:
uri: https://sail-ros-pkg.svn.sourceforge.net/svnroot/sail-ros-pkg/trunk
local-name: sail-ros-pkg
- svn:
uri: https://tum-ros-pkg.svn.sourceforge.net/svnroot/tum-ros-pkg
local-name: tum-ros-pkg
- svn:
uri: http://brown-ros-pkg.googlecode.com/svn/tags/brown-ros-pkg
local-name: brown-ros-pkg
- svn:
uri: http://alufr-ros-pkg.googlecode.com/svn/trunk/
local-name: alufr-ros-pkg
- svn:
uri: http://cu-ros-pkg.googlecode.com/svn/trunk
local-name: cu-ros-pkg
- svn:
uri: http://gt-ros-pkg.googlecode.com/svn/trunk
local-name: gt-ros-pkg
- git:
uri: http://robotics.ccny.cuny.edu/git/ccny-ros-pkg.git/
local-name: ccny-ros-pkg
- svn:
uri: http://svn.mech.kuleuven.be/repos/orocos/trunk/kul-ros-pkg
local-name: kul-ros-pkg
- svn:
uri: http://utexas-art-ros-pkg.googlecode.com/svn/trunk/stacks/
local-name: utexas-art-ros-pkg
- svn:
uri: https://usc-ros-pkg.svn.sourceforge.net/svnroot/usc-ros-pkg/trunk
local-name: usc-ros-pkg
- svn:
uri: https://wu-ros-pkg.svn.sourceforge.net/svnroot/wu-ros-pkg/stacks
local-name: wu-ros-pkg
- git:
uri: http://github.com/IHeartRobotics/iheart-ros-pkg.git
local-name: ihart-ros-pkg
- svn:
uri: https://jsk-ros-pkg.svn.sourceforge.net/svnroot/jsk-ros-pkg/trunk
local-name: jsk-ros-pkg
フォーマットはYAMLで, 分かりやすいと思います. 前半部分はcturtle_pr2all.rosinstallからの コピーです.
このファイルはhttp://garaemon.net/garaemon.rosinstall に置いてあるので, 以下のようにして rosinstallを呼び出します. (もちろんweb上におかなくてもOK)
$ rosinstall ~/ros http://garaemon.net/garaemon.rosinstall
ROSは非常によく出来ているので(特にツールチェインの充実がうれしい), ロボットを研究とかで 触っている人は, 試してみる価値があるかと思います.
個人的に気に入ってるのはrospyとpclです.
また, rosinstallで注意したほうがいいのは, 同じ名前のpackage, stackがあるとあれれな ことになります.
また, ここに上げたrosinstallは一部のレポジトリしかカバーできていませんが, いろいろな ところのrosレポジトリを入れておいて, つねにアンテナを張っておくと結構楽しいです.
jsk-rosemacs and emacs-settings
rosをemacs上で開発するには, rosemacs というemacs lispがあってこれを使うのが良いです. (とてもよく出来ている).
しかし, もしもあなたがrosemacsのキーバインドを覚えられないほど怠惰なら,jsk-rosemacs を 使ってみてはどうでしょうか?
jsk-rosemacsを使うと, anything.el で, rosのパッケージにアクセスできます.
インストールは, 拙作ながら, emacs-settingsを使うと便利です. anythingとかを 勝手にいれてくれます.
$ git clone git://github.com/garaemon/emacs-settings.git $ cd emacs-settings $ ./emacs-settings setup >> ~/.emacs $ ./emacs-settings install jsk-rosemacs
あとは, anythingのsourceの設定をします. 僕はこんな感じです
(require 'anything) (require 'anything-config) (require 'anything-rospack) (setq anything-sources (list anything-c-source-buffers anything-c-rospack-source anything-c-source-file-name-history anything-c-source-imenu anything-c-source-recentf ;;anything-c-source-man-pages ;;anything-c-source-info-pages anything-c-source-calculation-result anything-c-source-kill-ring ;;anything-c-source-bookmarks ;;anything-c-source-locate)) )) (global-set-key "\C-xb" 'anything) (global-set-key "\M-y" 'anything-show-kill-ring) (anything-iswitchb-setup) (define-key anything-map (kbd "C-p") 'anything-previous-line) (define-key anything-map (kbd "C-n") 'anything-next-line) (define-key anything-map (kbd "C-v") 'anything-next-source) (define-key anything-map (kbd "M-v") 'anything-previous-source) (global-set-key "\C-xp" (lambda () (interactive) (other-window -1)))
emacs-settingsを使うと, この設定でよければ以下でもってこれます.
$ ./emacs-settings add http://garaemon.net/emacs-settings-repo/garaemon.el $ ./emacs-settings install garaemon-anything-setting
実行するとこんな感じです.
infoまわり (cont.)
前回 からのつづきでsb-int:infoをみていきます.
struct type-info (src/compiler/globaldb.lisp)
これは, class-infoに所有されてる構造体です. 定義は以下のような感じ.
(defstruct (type-info #-no-ansi-print-object (:print-object (lambda (x s) (print-unreadable-object (x s) (format s "~S ~S, Number = ~W" (class-info-name (type-info-class x)) (type-info-name x) (type-info-number x))))) (:copier nil)) ;; the name of this type (name (missing-arg) :type keyword) ;; this type's class (class (missing-arg) :type class-info) ;; a number that uniquely identifies this type (and implicitly its class) (number (missing-arg) :type type-number) ;; a type specifier which info of this type must satisfy (type nil :type t) ;; a function called when there is no information of this type (default (lambda () (error "type not defined yet")) :type function) ;; called by (SETF INFO) before calling SET-INFO-VALUE (validate-function nil :type (or function null)))
まぁあんまよくわかりませんね. なんか保持してるんでしょう(ぇ. ちなみに, *info-types*にはtype-infoの全てのリストが保持されています.
* SB-C::*INFO-TYPES* #(#<:FUNCTION :KIND, Number = 0> #<:FUNCTION :TYPE, Number = 1> #<:FUNCTION :ASSUMED-TYPE, Number = 2> #<:FUNCTION :WHERE-FROM, Number = 3> #<:FUNCTION :INLINE-EXPANSION-DESIGNATOR, Number = 4> #<:FUNCTION :INLINEP, Number = 5> #<:FUNCTION :SOURCE-TRANSFORM, Number = 6> #<:FUNCTION :MACRO-FUNCTION, Number = 7> #<:FUNCTION :COMPILER-MACRO-FUNCTION, Number = 8> #<:FUNCTION :IR1-CONVERT, Number = 9> #<:FUNCTION :INFO, Number = 10> #<:FUNCTION :DEFINITION, Number = 11> #<:FUNCTION :STRUCTURE-ACCESSOR, Number = 12> #<:VARIABLE :KIND, Number = 13> #<:VARIABLE :ALWAYS-BOUND, Number = 14> #<:VARIABLE :TYPE, Number = 15> #<:VARIABLE :WHERE-FROM, Number = 16> #<:VARIABLE :XC-CONSTANT-VALUE, Number = 17> #<:VARIABLE :MACRO-EXPANSION, Number = 18> #<:VARIABLE :ALIEN-INFO, Number = 19> #<:VARIABLE :DOCUMENTATION, Number = 20> #<:TYPE :KIND, Number = 21> #<:TYPE :EXPANDER, Number = 22> #<:TYPE :DOCUMENTATION, Number = 23> #<:TYPE :TRANSLATOR, Number = 24> #<:TYPE :BUILTIN, Number = 25> #<:TYPE :COMPILER-LAYOUT, Number = 26> #<:TYPE :LAMBDA-LIST, Number = 27> #<:TYPE :SOURCE-LOCATION, Number = 28> #<:TYPED-STRUCTURE :INFO, Number = 29> #<:TYPED-STRUCTURE :DOCUMENTATION, Number = 30> #<:DECLARATION :RECOGNIZED, Number = 31> #<:DECLARATION :HANDLER, Number = 32> #<:ALIEN-TYPE :KIND, Number = 33> #<:ALIEN-TYPE :TRANSLATOR, Number = 34> #<:ALIEN-TYPE :DEFINITION, Number = 35> #<:ALIEN-TYPE :STRUCT, Number = 36> #<:ALIEN-TYPE :UNION, Number = 37> #<:ALIEN-TYPE :ENUM, Number = 38> #<:SETF :INVERSE, Number = 39> #<:SETF :DOCUMENTATION, Number = 40> #<:SETF :EXPANDER, Number = 41> #<:RANDOM-DOCUMENTATION :STUFF, Number = 42> #<:SOURCE-LOCATION :VARIABLE, Number = 43> #<:SOURCE-LOCATION :CONSTANT, Number = 44> #<:SOURCE-LOCATION :TYPED-STRUCTURE, Number = 45> #<:SOURCE-LOCATION :SYMBOL-MACRO, Number = 46> NIL NIL NIL NIL NIL NIL NIL NIL NIL NIL NIL NIL NIL NIL NIL NIL NIL)
class-infoとtype-info
ここでclass-infoとtype-infoについて簡単にまとめて図にしてみます.
function find-type-info (src/compiler/globaldb.lisp)
前回 , find-type-infoはtype-info-or-loseから呼ばれていました.
定義は
(defun find-type-info (name class) (declare (type keyword name) (type class-info class)) (dolist (type (class-info-types class) nil) (when (eq (type-info-name type) name) (return type))))
ここまでくると大体想像はついてましたが, class-infoのtypesから, nameにマッチする type-infoを探してくるようです.
やっぱこういう処理はdolistとreturnで書くのが速いのかなあ.
function get-info-value (src/compiler/globaldb.lisp)
ようやくget-info-valueにまで来ました. これは, sb-int:infoから直接呼ばれています.
定義.
;;; Return the value of NAME / TYPE from the first environment where ;;; has it defined, or return the default if none does. We used to ;;; do a lot of complicated caching here, but that was removed for ;;; thread-safety reasons. (defun get-info-value (name0 type &optional (env-list nil env-list-p)) (declare (type type-number type)) ;; sanity check: If we have screwed up initialization somehow, then ;; *INFO-TYPES* could still be uninitialized at the time we try to ;; get an info value, and then we'd be out of luck. (This happened, ;; and was confusing to debug, when rewriting EVAL-WHEN in ;; sbcl-0.pre7.x.) (aver (aref *info-types* type)) (let ((name (uncross name0))) (flet ((lookup (env-list) (let ((hash nil)) (dolist (env env-list (multiple-value-bind (val winp) (funcall (type-info-default (svref *info-types* type)) name) (values val winp))) (macrolet ((frob (lookup) `(progn (setq hash (globaldb-sxhashoid name)) (multiple-value-bind (value winp) (,lookup env name hash type) (when winp (return (values value t))))))) (etypecase env (volatile-info-env (frob volatile-info-lookup)) (compact-info-env (frob compact-info-lookup)))))))) (if env-list-p (lookup env-list) (lookup *info-environment*)))))
なんかけっこう重い.
aver(src/code/ealry-extentions.lisp)はassertみたいなものです. uncross(src/code/uncross.lisp)はまぁidentityと思ってOK.
globaldb-sxhashoidはsxhash の最適化版らしいです.
最後からみていくと,
(if env-list-p (lookup env-list) (lookup *info-environment*))
結局fletされてるlookupを呼ぶ, と.
lookupの定義は, dolistでenv-listを順にみていって, envの型に応じて, volatile-info-lookupかcompact-info-lookupか切り替えてます.
うーん, よくわからないですが, env-listの中からname / typeがみつかればそれを返し, みつからなかったら*info-types*からデフォルトを返すといったところでしょうか.
compact-info-envもvolatile-info-envもhashtableをもっていることに留意しておけば なんとなく推定できますね. つまり, このテーブルから引いてくると. (setf info)もこのテーブルに適切に値を入れるものであると 推定できます (あっているかはわからない).
(defstruct (compact-info-env (:include info-env) #-sb-xc-host (:pure :substructure) (:copier nil)) (table (missing-arg) :type simple-vector) (index (missing-arg) :type (simple-array compact-info-entries-index (*))) (entries (missing-arg) :type simple-vector) (entries-info (missing-arg) :type (simple-array compact-info-entry (*)))) (defstruct (volatile-info-env (:include info-env) (:copier nil)) (table (missing-arg) :type simple-vector) (count 0 :type index) (threshold 0 :type index))
infoまわり
sb-int:infoというのがsbclでは関数の定義されてる環境テーブルになっているようです. 今回はそこをみていきます. 前回
function sb-int:info (src/compiler/globaldb.lisp)
定義を見てみましょう.
(defun info (class type name &optional (env-list nil env-list-p)) (let ((info (type-info-or-lose class type))) (if env-list-p (get-info-value name (type-info-number info) env-list) (get-info-value name (type-info-number info)))))
実際の使われ方は,
(eq (info :variable :kind name) :macro)
とかのようです.
ためしに呼んでみます.
> (sb-int:info :variable :kind 'aa) :UNKNOWN NIL > (sb-int:info :variable :kind 'listp) :UNKNOWN NIL > (sb-int:info :function :kind 'listp) :FUNCTION T
なんとなくイメージはつかめますね.
function type-info-or-lose (src/compiler/globaldb.lisp)
ソースは色々けずると以下のような感じです.
(defun type-info-or-lose (class type) (prog1 (or (find-type-info type (class-info-or-lose class)) (error "~S is not a defined info type." type))))
さらに飛ばされます.
function class-info-or-lose (src/compiler/globaldb.lisp)
定義は以下のような感じ. *info-classes*というハッシュテーブルを引いてますね. そしてclassが シンボルであったら, plistを使ってメモ化してますね.
(defun class-info-or-lose (class) (declare (type keyword class)) (prog1 (flet ((lookup (class) (or (gethash class *info-classes*) (error "~S is not a defined info class." class)))) (if (symbolp class) (or (get class 'class-info-or-lose-cache) (setf (get class 'class-info-or-lose-cache) (lookup class))) (lookup class)))))
実際に呼んでみましょう.
> (SB-C::CLASS-INFO-OR-LOSE :variable) #<SB-C::CLASS-INFO :VARIABLE> > (SB-C::CLASS-INFO-OR-LOSE :function) #<SB-C::CLASS-INFO :FUNCTION> > (SB-C::CLASS-INFO-OR-LOSE :hoge) debugger invoked on a SIMPLE-ERROR in thread #<THREAD "initial thread" RUNNING {A9F59D1}>: :HOGE is not a defined info class.
*info-classes*とはなんでしょうか?
> (maphash #'(lambda (key value) (format t "key -> ~A, value -> ~A~%" key value)) sb-c::*info-classes*) key -> ALIEN-TYPE, value -> #<CLASS-INFO :ALIEN-TYPE> key -> DECLARATION, value -> #<CLASS-INFO :DECLARATION> key -> FUNCTION, value -> #<CLASS-INFO :FUNCTION> key -> RANDOM-DOCUMENTATION, value -> #<CLASS-INFO :RANDOM-DOCUMENTATION> key -> SETF, value -> #<CLASS-INFO :SETF> key -> SOURCE-LOCATION, value -> #<CLASS-INFO :SOURCE-LOCATION> key -> TYPE, value -> #<CLASS-INFO :TYPE> key -> TYPED-STRUCTURE, value -> #<CLASS-INFO :TYPED-STRUCTURE> key -> VARIABLE, value -> #<CLASS-INFO :VARIABLE>
全部で9種類あるようです. randam-documentationってなんだろう…
struct class-info (src/compiler/globaldb.lisp)
class-infoは, classの名前とtype-infoのリストを持つようです.
(defstruct (class-info (:constructor make-class-info (name)) #-no-ansi-print-object (:print-object (lambda (x s) (print-unreadable-object (x s :type t) (prin1 (class-info-name x) s)))) (:copier nil)) ;; name of this class (name nil :type keyword :read-only t) ;; list of Type-Info structures for each type in this class (types () :type list))
眠いので今日はここまで.
2010-08-19-02-02-00 Walker's alias methodをつかったParticle Filter
particle filter
最近研究で画像処理てきなことなどをしているわけですが, そこでかなり適当ですがParticle FilterをC++で 実装したので, 自分用のメモとして載せておきます.
実際研究で作ってるプログラムはもちっとこみいってますが, Particle Filterについてはここ を見てください. 復元抽出にWalker's alias methodをつかってます. これについてはこちら を参考に.
実装はC++で, すべてヘッダに書いてます(ぇ. バグとかあったら教えてもらえると嬉しいです. ちなみにC++素人です.
#include <vector> #include <boost/function.hpp> #include <boost/random.hpp> #include <boost/math/distributions/normal.hpp> #include <ctime> #include <iostream> namespace PF { // see http://ja.wikipedia.org/wiki/Boost double SampleNormal (double mean, double sigma) { using namespace boost; static mt19937 rng(static_cast<unsigned> (std::time(0))); normal_distribution<double> norm_dist(mean, sqrt(sigma)); variate_generator<mt19937&, normal_distribution<double> > normal_sampler(rng, norm_dist); return normal_sampler(); } class Particle { protected: double _weight; double _orig_likelihood; std::vector<double> _state; public: Particle() {}; Particle(const int dim): _weight(0.0), _state(dim, 0.0) {}; // copy constructor Particle(const Particle& orig): _weight(orig._weight), _orig_likelihood(orig._orig_likelihood) { _state = std::vector<double>(orig.getState().size()); for (size_t i = 0; i < orig.getState().size(); i++) _state[i] = orig.getStateValue(i); }; virtual ~Particle() {}; virtual inline const std::vector<double>& getState() const { return _state; }; /* does not overwrite _orig_likelihood */ virtual inline void updateWeight(const double weight) { _weight = weight; }; /* overwrite _orig_likelihood */ virtual inline void setWeight(const double weight) { _weight = weight; _orig_likelihood = weight; }; virtual inline double getWeight() const { return _weight; }; virtual inline double getStateValue(const size_t i) const { return _state[i]; }; virtual inline void setStateValue(const size_t i, const double val) { _state[i] = val; }; virtual inline double getOriginalLikelihood() const { return _orig_likelihood; }; virtual void sample(const std::vector<double>& mean, const std::vector<double>& cov) { for ( size_t j = 0; j < _state.size(); j++ ) _state[j] += SampleNormal(mean[j], cov[j]); }; virtual inline void zero() { for ( size_t j = 0; j < _state.size(); j++ ) _state[j] = 0.0; }; }; std::ostream& operator << (std::ostream& s, const Particle &p) { s << p.getState()[0] << ", " << p.getState()[1] << ", " << p.getState()[2] << ", " << p.getState()[3] << ", " << p.getState()[4] << ", " << p.getState()[5]; return s; } typedef enum { UPDATE_MEAN, UPDATE_MAX } UpdateParticleFilterMethod; class SimpleParticleFilter { // using gaussian for noising protected: boost::function<double (std::vector<double>)> _func; int _dim; int _particle_num; std::vector<double> _initial_noise_covariance; std::vector<double> _initial_noise_mean; std::vector<double> _step_noise_covariance; UpdateParticleFilterMethod _update_method; std::vector<Particle> _particles; Particle _representive_state; void normalizeWeight() { // calc weight summaction double sum = 0.0; for ( int i = 0; i < _particle_num; i++ ) sum += _particles[i].getWeight(); // too small weight summation, re-initialize particles if ( sum <= 1e-5 ) initParticles(); else for ( int i = 0; i < _particle_num; i++ ) _particles[i].updateWeight(_particles[i].getWeight() / sum); }; public: SimpleParticleFilter(int dim, int particle_num, std::vector<double> initial_noise_mean, std::vector<double> initial_noise_covariance, std::vector<double> step_noise_covariance, boost::function<double (std::vector<double>)> func, UpdateParticleFilterMethod method = UPDATE_MEAN): _func(func), _dim(dim), _particle_num(particle_num), _initial_noise_covariance(initial_noise_covariance), _initial_noise_mean(initial_noise_mean), _step_noise_covariance(step_noise_covariance), _update_method(method) { _representive_state = Particle(dim); initParticles(); }; virtual inline Particle getResult(){ return _representive_state; }; virtual ~SimpleParticleFilter() { }; /* sampling with replacement based on Walker's alias method @article{355749, author = {Walker, Alastair J.}, title = {An Efficient Method for Generating Discrete Random Variables with General Distributions}, journal = {ACM Trans. Math. Softw.}, volume = {3}, number = {3}, year = {1977}, issn = {0098-3500}, pages = {253--256}, doi = {http://doi.acm.org/10.1145/355744.355749}, publisher = {ACM}, address = {New York, NY, USA}, } implementation reference is: http://tolstoy.newcastle.edu.au/R/devel/05/06/1403.html */ virtual void genAliasTable(std::vector<int> &a, std::vector<double> &q) { /* generate an alias table, a and q */ std::vector<int> HL(_particle_num); std::vector<int>::iterator H = HL.begin(); std::vector<int>::iterator L = HL.end() - 1; for ( int i = 0; i < _particle_num; i++ ) q[i] = _particles[i].getWeight() * _particle_num; for ( int i = 0; i < _particle_num; i++ ) a[i] = i; // setup H and L for ( int i = 0; i < _particle_num; i++ ) if ( q[i] >= 1.0 ) *H++ = i; else *L-- = i; while ( H != HL.begin() && L != HL.end() - 1 ) { int j = *(L + 1); int k = *(H - 1); a[j] = k; q[k] += q[j] - 1; L++; if ( q[k] < 1.0 ) { *L-- = k; --H; } } } virtual inline int sampleWithReplacement(const std::vector<int>& a, const std::vector<double>& q) { using namespace boost; static mt19937 gen( static_cast<unsigned long>(time(0))); uniform_real<> dst(0.0, 1.0); variate_generator<mt19937&, uniform_real<> > rand(gen, dst); double rU = rand() * _particle_num; int k = (int)rU; rU -= k; /* rU - [rU] */ if ( rU < q[k] ) return k; else return a[k]; }; void resample() { std::vector<int> a(_particle_num); std::vector<double> q(_particle_num); genAliasTable(a, q); const static std::vector<double> zero_mean(_dim, 0.0); // escape the original list of particles std::vector<Particle> orig_particles = _particles; _particles.clear(); for ( int i = 0; i < _particle_num; i++ ) { int target_particle_index = sampleWithReplacement(a, q); Particle p = orig_particles[target_particle_index]; // add noise using gaussian p.sample(zero_mean, _step_noise_covariance); _particles.push_back(p); } }; void weight() { // call _func for each particles for ( int i = 0; i < _particle_num; i++ ) { double likelihood = _func(_particles[i].getState()); _particles[i].setWeight(likelihood); } normalizeWeight(); }; void update_mean() { //fill by zero _representive_state.zero(); // update for ( int i = 0; i < _particle_num; i++) { Particle p = _particles[i]; for ( int j = 0; j < _dim; j++ ) { double a = p.getStateValue(j) * p.getWeight(); double b = _representive_state.getStateValue(j); _representive_state.setStateValue(j, a + b); } } }; void update_max() { int max_index = 0; double max_weight = 0.0; for ( int i = 0; i < _particle_num; i++) { Particle p = _particles[i]; if ( p.getWeight() > max_weight ) { max_weight = p.getWeight(); max_index = i; } } _representive_state = _particles[max_index]; }; void update() { // update switch(_update_method) { case UPDATE_MEAN: update_mean(); break; case UPDATE_MAX: update_max(); break; default: break; } }; void initParticles() // finish { std::cout << "initParticles" << std::endl; _particles = std::vector<Particle>(_particle_num, _dim); // sampling... for ( int i = 0; i < _particle_num; i++ ) { Particle p(_dim); // w = 1 / N; p.setWeight(1.0 / _particle_num); p.zero(); p.sample(_initial_noise_mean, _initial_noise_covariance); _particles[i] = p; // update } }; inline std::vector<Particle> getParticles() { return _particles; }; }; }
夏だからsbclのソースコードを読もう
夏なのでsbclのコードでも読んでみようかと思います. 主にコンパイラ周りを. オイラに読み解けるのか…?
どっかにwikiみたいなの置いたほうが良いかなー
macro defun (src/code/defboot.lisp)
(defun add (a b) (+ a b))
というところからスタートしてみたいと思います.
* (macroexpand '(defun add (a b) (+ a b))) (PROGN (EVAL-WHEN (:COMPILE-TOPLEVEL) (SB-C:%COMPILER-DEFUN 'ADD 'NIL T)) (EVAL-WHEN (:LOAD-TOPLEVEL :EXECUTE) (SB-IMPL::%DEFUN 'ADD (SB-INT:NAMED-LAMBDA ADD (A B) (BLOCK ADD (+ A B))) NIL 'NIL (SB-C:SOURCE-LOCATION))))
らしいので, とりあえずSB-IMPL::%DEFUNをみてみます
function SB-IMPL::%DEFUN (src/code/defboot.lisp)
定義は
(defun %defun (name def doc inline-lambda source-location) (declare (type function def)) (declare (type (or null simple-string) doc)) (aver (legal-fun-name-p name)) ; should've been checked by DEFMACRO DEFUN (sb!c:%compiler-defun name inline-lambda nil) (when (fboundp name) (/show0 "redefining NAME in %DEFUN") (style-warn 'sb!kernel::redefinition-with-defun :name name :old (fdefinition name) :new def :new-location source-location)) (setf (sb!xc:fdefinition name) def) (sb!c::note-name-defined name :function) (when doc (setf (%fun-doc def) doc)) name)
適時!は-に読み替えます.
結局,
(sb-c:%compiler-defun 'add (SB-INT:NAMED-LAMBDA ADD
(A B)
(BLOCK ADD (+ A B))) nil)
が呼ばれるのかな.
function SB-C:%COMPILER-DEFUN (src/compiler/ir1tran-lambda.lisp)
IR1はthe first intermediate representationのことらしい.
定義
(defun %compiler-defun (name lambda-with-lexenv compile-toplevel) (let ((defined-fun nil)) ; will be set below if we're in the compiler (when compile-toplevel (setf defined-fun (get-defined-fun name)) (when (boundp '*lexenv*) (remhash name *free-funs*) (aver (fasl-output-p *compile-object*)) (if (member name *fun-names-in-this-file* :test #'equal) (warn 'duplicate-definition :name name) (push name *fun-names-in-this-file*)))) (become-defined-fun-name name) (cond (lambda-with-lexenv (setf (info :function :inline-expansion-designator name) lambda-with-lexenv) (when defined-fun (setf (defined-fun-inline-expansion defined-fun) lambda-with-lexenv))) (t (clear-info :function :inline-expansion-designator name))) ;; old CMU CL comment: ;; If there is a type from a previous definition, blast it, ;; since it is obsolete. (when (and defined-fun (eq (leaf-where-from defined-fun) :defined)) (setf (leaf-type defined-fun) ;; FIXME: If this is a block compilation thing, shouldn't ;; we be setting the type to the full derived type for the ;; definition, instead of this most general function type? (specifier-type 'function)))) (values))
結局,
(SB-KERNEL:BECOME-DEFINED-FUN-NAME 'add) (setf (sb-int:info :function :inline-expansion-designator 'add) (SB-INT:NAMED-LAMBDA ADD (A B) (BLOCK ADD (+ A B))))
が実行されるのかな?
Date: 2010-09-01 02:11:17 JST
HTML generated by org-mode 7.01h in emacs 23