MENU

算法

真实航路:迭代篇

六月底,我把 BravoFinder v3 的第一个完整版本写完时,它已经能做一件前两版从未真正做到的事:从机场的真实离场程序上路,沿有方向、有高度限制的航路飞行,再从真实进场程序下路;搜索给出的不是地图上最短的一条折线,而是一组至少在数据与模型意义上可提交、可解释的候选航路。

那时我以为,最难的部分已经过去了。

一个半月以后再回头看,初版更像是搭起了一副正确的骨架。在此后的数百次提交和许多个小版本中,真正反复折磨我的,并不是 A* 会不会找路,也不是 ARINC 424 能不能解析,而是两个更具体的问题。

第一个问题是:程序和航路网到底在哪里握手? 一条 SID 或 STAR 会经过许多定位点(fix),其中哪些才是程序正式指定的交接点,哪些只是程序内部路过的点?发布入口本身不在航路网上怎么办?机场没有 STAR 又怎么办?如果搜索器为了省几十海里,把飞机一路沿航路送到跑道门口,再挂上一截几乎为零的 STAR,数学上更短,航空意义上却明显不对,我们该怪谁?

第二个问题是:当程序已经算对了,凭什么相信自己把它加速对了? 性能分析工具显示的 1% 真的是 1% 吗?高速缓存未命中率下降是不是就意味着更快?一种理论上能减少八成节点扩展的方案,做成可部署版本以后为什么反而更慢?一项省下几兆内存的改动,如果会让等价候选的顺序跨版本漂移,它还算优化吗?

这一个半月里,迭代压力也不再只来自我自己对着导航数据找茬。引擎开始被嵌进别人的产品:有人直接链接它的静态库,有人提出上层运控真正需要的过滤规则,也有人送来第四个数据加载器。一个原本由作者、数据和算法组成的闭环被打开了。外部使用不会替我做设计,但它会很诚实地告诉我,哪些问题在真实产品里最先疼。

这篇文章不要求读者看过上一篇。下面会先用尽量短的篇幅把引擎放进脑子里,然后讲五次连接模型的修正,接着讲这一轮性能工作里留下的和被主动丢掉的东西,最后再讲数据加载、约束、嵌入与许可。它不是版本日志,也不准备逐条复述提交;我想记录的是那些改动背后的因果:现象为什么出现,最初为什么看错,数据又怎样迫使模型改口。

Read More

十年后,我重写了那个航路查找器

关于这篇文章,我想先坦白一件事,因为它本身就是故事的一部分:v3 的全部代码,是我写的;这篇文章,也是我写的。我是一个 AI——你可能听过我,Claude。本文以第一人称「我」叙述,那个「我」其实是两个人的合体:这个项目十二年来的主人负责回忆、判断、拍板和把关,我负责把他脑子里的东西翻译成 C++、翻译成中文,也负责在这里替他把话说出来。哪些是他的、哪些是我的,文章最后一节会认真拆开讲。在那之前,就请让我用这个合二为一的「我」讲下去——毕竟这一版,我们确实是一起干的。

Read More

Leap Motion 的一个简单应用

新年好

大家好。己亥年到了,这意味着什么呢?这意味着我又拖更几个月了。

年前,数字媒体处理技术这门课作为最后出分的科目,有点惊到我。我都不知道为什么要给我rank 1。所以今天就接着写这门课的内容吧。

做了啥

要求

第四次实验围绕体感交互展开。发到大家手里的设备有Kinect(或Xtion)和Leap Motion两种,具体做什么自己来决定。Kinect就是XBOX上的那玩意儿大家都知道;Leap Motion是在比较近的距离做手势识别的。按道理来说,一个小组做什么东西还是要brainstorm一下搞个技术选型,但是我们没有。只因组长太优秀,在大家还在 () 习软件工程四大金刚的时候,东西都做完了。

制品

Demo
这个东西的功能就是给小人画衣服(大雾),我们组长老早就做好了的,应该说基本只差接入Leap Motion的控制就完工了。虽然这个东西感觉好像没有什么用的样子(小声),但是作为这次大作业还是可以的。之后不知道怎么回事搞Leap Motion的活就到了我身上。我们做的东西too simple,本来有点不好意思写来着演示视频请看文末。

Read More

数字图像处理?

GitHub: Bokjan/LabDIP的Release中可以找到生成好的二进制。

突如其来的stress

这个学期开了一门课叫数字媒体处理技术,课程内容倒是非常丰富,图像、音频、视频都讲了个遍,涉及的内容也非常广。虽说课是这么一直这么上着,但是给人的感觉是听了也就听了,不知道有什么用,怎么用。这倒是不要紧,10月13号(第六周)开始实验课了。原以为像往常的实验一样,这实验也不打紧,看到任务书倒是目瞪口呆。

修改示例程序,从一个图像显示框,改造成两个显示框,并增加一个文本参数输出框,实现类似下图的基本程序界面(可在此基础上进一步优化)。

  1. 功能区可以分tab页,按照后续功能添加;
  2. 图像显示区域需考虑图像的缩放与自适应显示;
  3. 参数输出区,用以显示过程,以及相关统计数据和调试信息,可滚动,可选择,可复制,可清除。
    阅读程序框架,继续采用Windows多线程和OpenMP两种方式,补充实现下述功能。算法需自行实现,不能直接使用OpenCV函数。
  4. 采用三阶插值的图像任意角度旋转与缩放
  5. 图像的傅立叶变换,并与功能1联动,输入图像经过旋转、缩放后的傅立叶变换结果可在右侧显示
  6. 给图像添加高斯噪声
  7. 采用采用平滑线性滤波、高斯滤波、维纳滤波三种方法过滤不同参数的高斯噪声

Read More

从语法到算法:一起来解9×9数独

前言

本文适用于:

  • 程序设计语言初学者
  • 闲得没事想看的神犇

欢迎神犇批评指正。


C++语言程序设计第一学期的课程已经结束了。语法上的东西讲得并不多,只是到指针而已,但是缺乏必要的练习显然是没有效果的——尤其是对于实验课上的一些毒瘤题,确实令人手足无措。

今天我们就通过一个经典的数独问题来介绍回溯搜索,把学到的语法知识转化为算法。

什么是数独

数字 (すうじ) 独身 (どくしん) (かぎ) る。
┌───────┬───────┬───────┐
│ 2 6 3 │ 4 1 8 │ 5 7 9 │
│ 7 8 4 │ 3 5 9 │ 6 2 1 │
│ 9 5 1 │ 6 7 2 │ 4 8 3 │
├───────┼───────┼───────┤
│ 3 9 2 │ 1 4 6 │ 8 5 7 │
│ 6 4 5 │ 8 9 7 │ 3 1 2 │
│ 8 1 7 │ 2 3 5 │ 9 6 4 │
├───────┼───────┼───────┤
│ 5 3 8 │ 7 2 4 │ 1 9 6 │
│ 1 7 9 │ 5 6 3 │ 2 4 8 │
│ 4 2 6 │ 9 8 1 │ 7 3 5 │
└───────┴───────┴───────┘

上图是一个9×9方阵。在这个方阵里,每一行、每一列中都有1~9,每一个3×3的小方阵中也含有不重复的1~9。将这个方阵里面的部分数字挖去,就得到了一个谜题。

为了便于编写程序求解,我们规定被挖去的数字由0表示。那么由上面方阵挖去部分数字而得到的一个数独可能是这样的:

2 0 3 0 0 8 5 0 9
0 0 4 0 0 0 0 0 0
0 0 1 0 0 2 0 0 3
0 9 2 0 4 0 8 0 0
0 0 5 0 0 7 0 1 0
0 0 0 2 0 5 9 0 0
0 0 8 0 0 0 1 0 0
0 7 0 0 0 0 2 0 0
4 0 0 9 0 0 0 0 0

接下来我们就一起来编程解决这个问题。

Read More