简介:Swarm 2.1 仿真工具面向多智能体系统建模与复杂系统行为分析的学习者和研究者,适合人工智能、分布式计算、网络优化及生物启发式算法等场景的仿真实验。压缩包共221个文件、约691KB,以73个m实现文件、58个h头文件、27个o编译产物为主,辅以17个changelog、16个makefile、12个readme及少量scm、exe、license等,既保留源码结构,也便于查看构建记录和版本变更。已有205人学习,说明其在相关课程与科研入门中有一定参考面。使用者可围绕智能体行为规则、FIPA-ACL通信、Boids群集模拟、可视化观察与评估调试等环节展开实践,借助示例和构建脚本理解多智能体仿真从建模到运行的完整脉络,并对照变更日志排查兼容性问题。
1. 装 Swarm 2.1 之前,先把版本兼容这关过了
有个开发者把 swarm2.1 仿真工具 的压缩包解到/opt下,./configure一路绿灯,make跑到第三分钟突然停在一堆 Objective-C 头文件找不到的报错上,回头再翻安装说明,才发现自己用的是系统自带的编译器和 64 位 JDK。Swarm 2.1 是个有年头的主体仿真平台,内核用 Objective-C 写,Java 层通过 JNI 挂上去,它对工具链版本、库的 ABI、图形后端都挑得很。装不对的典型表现不是"报错退出",而是编译能过、示例一启动就黑屏或者直接段错误,排查起来像拆黑匣子。这套环境适合做多主体仿真、群体行为建模、教学演示的人,尤其是需要跑老论文复现的那批人。下面按我自己装过的顺序,把依赖、编译、配置、验证一步步走完。
2. 依赖与工具链:编译 Swarm 2.1 需要的那几样东西
2.1 JDK 选择:为什么我锁死在 JDK 8 的 32 位构建
Swarm 2.1 的 Java 支持层是围绕上世纪的 JNI 头文件写的,jni.h里的类型宽度、JNIEnv的结构布局跟后来的 JDK 没本质冲突,真正出问题的是 ABI 和库的位数。发行包里的 Makefile 会把-m32之类的标志散落在各个子目录,如果你装的是纯 64 位 JDK,编译 Java 绑定那一段就会在链接期报undefined reference to JNI_CreateJavaVM,或者更隐蔽地过了编译、运行时System.loadLibrary直接抛UnsatisfiedLinkError。
我一般的做法是单独装一套 32 位 JDK 8,不覆盖系统默认的 Java。常见做法是从发行版仓库装openjdk-8-jdk的 i386 版本,或者直接用官方提供的 32 位压缩包解到/opt/jdk8-x86,再在环境变量里按需切换。这里不要图省事去改/usr/bin/java的软链,系统里别的构建脚本会跟着遭殃。
# 解压独立的 32 位 JDK 到指定目录,不影响系统默认 java tar -zxvf jdk-8u202-linux-i686.tar.gz -C /opt/ mv /opt/jdk1.8.0_202 /opt/jdk8-x86 # 验证位数,输出必须是 32-bit /opt/jdk8-x86/bin/java -version 2>&1 | head -3-version输出里的32-Bit是硬指标,如果这里显示 64-Bit,后面所有 Java 相关的步骤都别往下走了,先换包。/opt/jdk8-x86这个路径不是随便起的,后面configure的--with-jdkdir要一字不差地指过来。
如果你的机器是纯 64 位系统、装不了 32 位运行时,那就只能走"只编译 Objective-C 内核、放弃 Java 层"的路子,代价是所有 Java 写的示例模型跑不了。这一点要在动手之前想清楚,别装到一半才发现方向错了。
2.2 基础编译工具与图形库
Swarm 的图形显示依赖 X11,早期版本还绑了 BLT 这个 Tk 扩展做绘图控件。缺了它们,configure会在检查阶段给出checking for X... no,然后默默把图形部分关掉,编译出来的东西能跑批处理模式、但一开可视化窗口就报cannot open display。
需要提前备齐的软件包大致是这几类:编译工具链(gcc、make、binutils)、X11 开发头文件(libx11-dev、libxext-dev、libxmu-dev)、Tk/Tcl 开发库,以及zlib这类基础库。不同发行版的包名有差异,我一般先用一条命令把"有没有"确认一遍,缺什么补什么,而不是一上来就全量装。
# 检查关键组件是否齐全,缺哪个补哪个 which gcc make ld pkg-config --exists x11 && echo "x11 ok" || echo "x11 missing" pkg-config --exists tk && echo "tk ok" || echo "tk missing" ls /usr/include/X11/Xlib.h 2>/dev/null && echo "Xlib header ok"pkg-config --exists返回 0 表示能找到对应的.pc描述文件,比单纯ls看目录更可靠,因为它同时验证了版本区间。/usr/include/X11/Xlib.h是 X11 头文件的标志性文件,configure阶段找的就是它。如果tk那一行报 missing,补上开发包之后再重跑一遍检查,不要带着缺失项硬编译——Swarm 的配置脚本对可选依赖的判断逻辑很老派,缺了不报错,只会在链接期给你一堆undefined reference to Tk_Init。
还有一个容易被忽略的点:gcc版本。新版 GCC(9 以上)默认按 C99/C11 语义处理,对老代码里隐式函数声明、char*与字符串常量混用这类写法会直接报错而不是警告。我一般会加上-fpermissive或者干脆用gcc-8来编译,具体在下一章的configure里一起说。
2.3 目录规划与环境变量
我习惯把 Swarm 装在一个独立前缀下,跟系统目录完全隔离,这样卸载就是rm -rf,升级也不会互相污染。目录规划大致是:源码解压到/opt/src/swarm-2.1,安装前缀用/opt/swarm-2.1,示例模型和自建模型分别放在$SWARMHOME/examples和$HOME/swarm-models下。
环境变量集中在~/.swarmrc里维护,用的时候source一下,不写进全局的/etc/profile。原因是同时可能有别的项目要用系统默认 Java,全局改 PATH 是自找麻烦。
# ~/.swarmrc —— Swarm 2.1 专用环境,按需 source export SWARMHOME=/opt/swarm-2.1 export SWARMSRC=/opt/src/swarm-2.1 # 优先用 32 位 JDK,保证 JNI 链接一致 export JAVA_HOME=/opt/jdk8-x86 export PATH=$JAVA_HOME/bin:$SWARMHOME/bin:$PATH # 运行时找 .so,编译时找头文件,Java 找 jar export LD_LIBRARY_PATH=$SWARMHOME/lib:$LD_LIBRARY_PATH export C_INCLUDE_PATH=$SWARMHOME/include:$C_INCLUDE_PATH export CLASSPATH=$SWARMHOME/share/swarm/swarm.jar:$CLASSPATHSWARMHOME是安装前缀,Swarm 自己的 Makefile 和启动脚本大量引用这个变量,写错一个字母后面全乱。LD_LIBRARY_PATH让运行时能找到libswarm.so,这是最容易漏的一条——编译期有-L顶着,运行期没有它就报error while loading shared libraries。CLASSPATH里的swarm.jar位置在 2.1 里通常是share/swarm/目录,装完之后用find确认一下实际路径再写死,别照抄。
提示:
source ~/.swarmrc之后用echo $SWARMHOME和java -version各确认一次,这两个变量没有同时生效的话,后面编译阶段会以很难看懂的方式失败。
3. 编译安装 Swarm 2.1:从 configure 到 make install
3.1 configure 的关键参数怎么给
Swarm 2.1 的构建系统是经典的 autoconf 那一套,./configure --help能列出全部开关,但真正需要你操心的就那么几个:安装前缀、X11 支持、JDK 路径、Java 版本号。其余保持默认即可,参数给多了反而容易触发老脚本里的分支判断 bug。
cd /opt/src/swarm-2.1 # 关键参数逐条给,日志留档方便回查 ./configure \ --prefix=/opt/swarm-2.1 \ --with-x \ --with-jdkdir=/opt/jdk8-x86 \ --with-javamajor=1.8 \ --disable-dependency-tracking \ 2>&1 | tee configure.log--prefix决定最终安装位置,必须和SWARMHOME完全一致。--with-x显式开启图形支持,不加这个开关时脚本会自动探测,探测结果不稳,显式声明更保险。--with-jdkdir指向 2.1 节准备的那套 32 位 JDK,注意是 JDK 根目录而不是bin子目录。--with-javamajor告诉脚本按哪个 Java 版本生成绑定代码,填1.8而不是8,老脚本认的是这种点分格式。--disable-dependency-tracking是经验项,它能避开老版本 automake 生成的依赖规则在并行 make 时的竞态,编译时间略长但更稳。
跑完之后先别急着 make,翻一遍configure.log末尾的 summary 段。我关注三行:X11 是否 detected、Java 是否 enabled、jni.h的路径是否指向/opt/jdk8-x86/include。任何一行不对,回到上一章补依赖或者改参数,不要带着错误配置往下编译——那只会把问题推迟到链接阶段,排查成本翻倍。
3.2 make 阶段的报错与告警处理
make是整个安装里最容易翻车的一段。老代码在新编译器下会冒出一堆 warning,大部分可以忽略,但有几类必须停下来处理。我一般的判断标准是:warning 里出现implicit declaration of function或incompatible pointer type的,先记下来;出现error:的直接停。
# 单线程先跑一遍,看清楚第一个错误点 make 2>&1 | tee make.log # 确认没有 error 之后再用并行加速重跑 make -j2 2>&1 | tee -a make.log第一次刻意用单线程,是为了让make.log里第一个 error 就是真正的根因。并行 make 会把多个子目录的输出搅在一起,第一次装的人很容易被后面的连锁错误带偏。等单线程能过、只是想加快速度时再上-j2,-j的数字别开太大,老 Makefile 里的依赖声明不完整,-j8有概率编出半成品。
针对隐式函数声明的告警,可以在configure前给CFLAGS追加宽松选项:
# 让老代码在新 GCC 下按旧语义编译 export CFLAGS="-O2 -fpermissive -Wno-implicit-function-declaration -Wno-pointer-sign" ./configure --prefix=/opt/swarm-2.1 --with-x \ --with-jdkdir=/opt/jdk8-x86 --with-javamajor=1.8-fpermissive把一部分原本的 error 降级为 warning,这是编译上世纪末 C 代码的常用手段,代价是失去了部分类型检查,所以只在确认源码没被改动过的情况下用。-Wno-implicit-function-declaration只是把噪音关掉,不改变行为;如果关掉之后链接仍然报undefined reference,说明那个函数真的不存在,得回去查是不是某个可选依赖没装。
make过了之后执行make install,这一步相对安静,主要工作是拷贝头文件、库、jar 包和示例到--prefix指定的目录。
3.3 安装后的目录结构与 CLASSPATH 校准
装完先别急着跑示例,花两分钟把目录结构对一遍。Swarm 2.1 的安装结果大致分四块:bin放可执行文件和启动脚本,lib放.so动态库,include放 Objective-C 和 C 的头文件,share/swarm放 Java 的 jar 包和资源。这个布局跟SWARMHOME那套环境变量是严格对应的,任何一块位置不对,运行时就会在某个环节断掉。
# 结构核对:四类产物各就各位 find /opt/swarm-2.1 -maxdepth 2 -type d | sort ls -l /opt/swarm-2.1/lib/libswarm* ls -l /opt/swarm-2.1/share/swarm/*.jar第一条命令看目录骨架,正常情况下应该能看到bin、include、lib、share四个顶层目录。第二条确认libswarm.so存在且不是零字节——编译中断留下的空文件很常见,ls -l看大小最直接。第三条确认swarm.jar的实际路径,如果它出现在share/swarm/以外的地方,把CLASSPATH改成真实路径,别硬按文档写。
jar 包路径确认之后,建议做一次最小化的加载测试,不涉及图形、不涉及模型:
# 只验证 jar 能被 JVM 找到并加载核心类 javac -version java -cp $SWARMHOME/share/swarm/swarm.jar -version 2>&1 | head -5-cp显式指定 classpath,避免依赖环境变量是否 source 过,这样测出来的结果才干净。如果这里报Could not find or load main class,问题就在 jar 路径或者 JDK 版本上,跟后面的模型代码无关,别混在一起查。
4. 跑通第一个仿真:示例模型的配置与运行
4.1 示例目录的构成与启动方式
安装完成后$SWARMHOME/examples下会有一批自带模型,其中结构最简单、最适合拿来做冒烟测试的是 heatbugs 这类格子上的主体移动模型。它的目录里通常有三样东西:模型的源码、一个Makefile、以及若干.params或.scm形式的配置文件。启动脚本一般也在这一层,名字可能是run.sh或者直接由 Makefile 的run目标驱动。
cd $SWARMHOME/examples/heatbugs ls -l # 先编译模型本身,再谈运行 make 2>&1 | tee build.logls那一步不是走过场,要看清 Makefile 里引用的路径是不是指向$SWARMHOME。老版本示例的 Makefile 有硬编码相对路径的习惯,换个安装前缀就跑不通。make的输出里如果出现Swarm相关的头文件路径,说明C_INCLUDE_PATH生效了;如果报找不到swarm.h,回到 2.3 节检查那个变量。
模型编译通过后,用批处理模式启动一次,绕开图形界面,把"能不能跑"和"图形能不能显示"这两件事分开验证:
# 批处理模式跑一轮,不弹窗,先确认仿真内核正常 ./heatbugs -b 1 -t 10 2>&1 | tee run-batch.log-b表示批处理,-t是仿真步数,不同示例的参数名可能略有差异,用./heatbugs --help看实际支持项。批处理能跑完并输出统计行,说明主体调度、随机数、数据输出这几条链路都是通的,剩下的问题就只在显示层。
4.2 参数文件与运行日志怎么读
Swarm 的模型参数不是写在代码里,而是通过外部参数文件注入,这是它跟很多现代仿真框架不一样的地方。参数文件是纯文本,一行一个键值,改动不需要重新编译,这点在做参数扫描时很省事。我一般的做法是把默认参数文件复制一份成my.params,只在副本上改,保持原始文件干净,出问题能对照。
# my.params —— heatbugs 常用参数示例 worldSizeX=100 # 格子世界横向尺寸,影响内存与单步耗时 worldSizeY=100 # 纵向尺寸,与上面保持同等量级 nBugs=200 # 主体数量,先小后大,便于观察 evaporationRate=0.01 # 热量蒸发率,影响收敛速度 runSteps=500 # 总仿真步数,批处理模式下按此循环worldSizeX/Y决定空间规模,两个值乘起来就是单步要遍历的格子数,开到 500×500 以上时批处理耗时会明显上升,做验证时先用 100×100。nBugs是主体数量,这个值在图形模式下超过几百就会卡,因为每个主体都要画一次。evaporationRate影响模型的稳态行为,改这个值主要是观察结果差异,跟安装无关,但它是最容易被误认为"装坏了"的参数——调到极小时模型看起来像卡住,实际是在慢慢收敛。runSteps只在批处理模式生效。
日志方面重点看两类输出:启动时的类加载信息,和每一步结束时的统计行。前者能暴露 classpath 缺项,后者能暴露模型逻辑异常。如果启动打印出一长串Loading class ...之后停住不动,八成是在等 X11 连接,而不是在计算。
4.3 换成自己的模型要改哪几处
跑通示例之后,多数人的下一步是把自己的模型挂上去。Swarm 2.1 的模型目录结构比较固定,复制一份示例目录改名,然后改三个地方就能跑起来:Makefile 里的目标名、参数文件里的模型类名、以及启动脚本里的主类。
# 复制示例作为新模型骨架 cp -r $SWARMHOME/examples/heatbugs $HOME/swarm-models/mymodel cd $HOME/swarm-models/mymodel # 清掉示例编译产物,避免残留 .o 干扰 make cleanmake clean这一步别省,复制过来的.o文件和.class文件里记录的是原路径,不清掉的话新目录编译时可能直接复用旧产物,表现为"改了代码但行为没变",这种问题查起来非常费时间。改 Makefile 时重点看SWARMHOME引用和TARGET变量,前者保证链接到正确的库,后者决定生成的可执行文件名。参数文件里的主类名要和 Java 源码里的package和类名对齐,大小写敏感,写错就是ClassNotFoundException。
注意:自建模型目录不要放在
$SWARMHOME下面。安装目录保持只读语义,升级或者重装时直接整目录替换,自己的模型不会跟着被覆盖。
5. 避坑与排查:Swarm 2.1 装完跑不起来的几种典型情况
5.1 编译与链接阶段
现象:configure全部通过,make在链接 Java 绑定库时报undefined reference to JNI_CreateJavaVM。原因:--with-jdkdir指向的 JDK 位数与编译出的目标文件位数不一致,或者该路径下只有 JRE 没有libjvm.so。解决:用file确认目标文件是 32 位,再find /opt/jdk8-x86 -name "libjvm.so"确认库存在,两者位数必须一致;只有 JRE 的话换完整 JDK。
现象:make报大量implicit declaration of function 'xxx',最后在链接期失败。原因:新版 GCC 对隐式声明从严处理,老代码缺少头文件包含。解决:按 3.2 节追加-fpermissive等宽松选项重编;如果关掉告警后仍报undefined reference,说明是真实缺依赖,回去补对应的开发包。
现象:make install成功,但lib目录下libswarm.so大小为 0。原因:上一次编译中断留下的空文件,install目标只做拷贝不做校验。解决:make clean后完整重编,装完用ls -l看文件大小,几百 KB 以上才算正常。
5.2 运行与显示阶段
现象:批处理模式能跑完,带图形启动时报cannot open display或直接黑屏退出。原因:DISPLAY环境变量没设,或者 X11 开发库装了但运行时库缺失。解决:本地桌面会话下echo $DISPLAY应有值;远程场景下确认 X11 转发已开启,或者干脆只用-b批处理模式做验证,图形另找有桌面的机器。
现象:启动时报error while loading shared libraries: libswarm.so: cannot open shared object file。原因:LD_LIBRARY_PATH没生效,或者source ~/.swarmrc只在新开的 shell 里做过。解决:echo $LD_LIBRARY_PATH确认包含$SWARMHOME/lib;用ldd ./heatbugs | grep swarm看解析结果,显示not found就是路径问题。
现象:模型跑起来但结果全是零,或者主体数量跟参数文件里写的对不上。原因:参数文件没被加载,程序用了内置默认值;或者参数文件名与启动脚本里写的不一致。解决:在启动命令里显式指定参数文件路径,别依赖当前目录;启动日志里通常会打印实际加载的文件名,对着看一眼就知道有没有读错。
6. 装完怎么验证:三步确认这套仿真环境真的可用
验证这件事我不喜欢一次性全上,容易把问题搅在一起。我的习惯是分三层,每层都有明确的通过标准,前一层不过就不进下一层,这样出错时能立刻定位到是哪一层的问题。
第一层验工具链,只看编译能力,不碰运行:
# 写一个最小 C 程序,链接 Swarm 库并调用一个核心符号 cat > /tmp/t.c <<'EOF' #include <swarm.h> int main(void) { return 0; } EOF gcc /tmp/t.c -I$SWARMHOME/include -L$SWARMHOME/lib -lswarm -o /tmp/t && echo "link ok"-I和-L分别指定头文件和库路径,-lswarm触发实际链接。能输出link ok说明头文件和动态库都完整,这一步过了,后面就不会再出"找不到符号"这类低级问题。
第二层验运行内核,用批处理模式跑示例,看统计输出:
| 检查项 | 通过标准 | 不通过时的方向 |
|---|---|---|
| 进程退出码 | echo $?为 0 | 看 run-batch.log 首个异常行 |
| 统计输出 | 每步有数值变化的统计行 | 参数文件是否被加载 |
| 运行时长 | 与步数近似线性 | 主体数量或空间规模过大 |
| 内存占用 | 稳定不持续上涨 | 主体创建后未回收 |
第三层验图形与 Java 层,在有桌面的环境下启动一次可视化:
# 图形模式启动,观察窗口能否正常绘制并响应 ./heatbugs -t 50 2>&1 | tee run-gui.log通过标准是窗口出现、格子被逐步染色、关闭窗口后进程正常退出且退出码为 0。如果窗口出现但内容不刷新,多半是 Tk/BLT 版本不匹配;如果进程结束时报Segmentation fault,回去看run-gui.log末尾几行,通常是某个绘图回调里访问了已释放的对象。
三层都过之后,我还会做一件看起来多余的事:把整套验证命令写成一个verify.sh放在模型目录旁边,以后每次换机器、升级系统库之后重跑一遍。这个脚本里有环境变量检查、链接测试、批处理跑 10 步、图形启动超时退出这四个动作,全程不到一分钟,但它替我挡过好几次"系统更新之后某个库悄悄变了 ABI"的情况。
血泪经验是:这类老平台的依赖关系是隐式的,ldd看不出来的东西太多,装的时候顺手把每一步的日志留下来——configure.log、make.log、run-batch.log,出问题时这三个文件比任何排查思路都管用。从那以后我每次装完 Swarm 2.1 都强制走一遍这三层验证,哪怕只是换了个目录重装也一样,图的就是省下后面那几个小时。发行包里该有的头文件、库、jar 和示例都在,按第 2 章的目录规划解压、按第 3 章编译安装,再拿第 6 章这套流程卡一遍,基本就能直接开工了。希望帮到你。
本文还有配套的精品资源,点击获取