Resources for Prospective Students

(最后更新:2024 年 4 月 8 日)

我对编程语言的多个研究话题都很有兴趣,尤其是形式化验证、程序分析以及概率编程。 我目前的研究项目主要涉及资源安全的系统编程、可编程贝叶斯推断、量化程序分析以及面向证明的编程语言。

  • 如果你想了解我目前的研究项目和方向,可以参考下方的列表
  • 如果你想看一下我申请教职时关于软件中的随机性的构想,可以参考我的研究陈述(英文)
  • 如果你比较关心我在教学和指导学生上的经验和方法,可以参考我的教学陈述(英文)
  • 如果你有关于我、北京大学或者程序设计语言研究室的具体问题,可以参考下面的 Q&A 或者发邮件给我。

Q&A

“你招收学生吗?”
是的! 我计划每年招一到两个博士生,也欢迎感兴趣的硕士和本科生。
“我需要有特定的研究履历吗?我需要清楚自己要做什么特定的项目吗?”
简单的回答是“不用”。 有编程语言或软件工程相关的研究经验当然很好,但不是必需的。 相比于过往的经验,更重要的是你知道自己对什么感兴趣,并且有动力用四到五年的时间去探索一个领域内的各种问题。
“我可以做机器学习、操作系统、数据库等等相关的项目吗?”
没问题,这些领域与编程语言都有相关的交叉领域。 以下是一些跨领域的研讨会,仅作参考: Symposium on Machine ProgrammingWorkshop on Languages for InferenceWorkshop on Programming Languages and Operating SystemsSymposium on Database Programming Languages
“北京大学有什么优势?在那儿可以跟哪些老师合作?”
北京大学拥有世界一流的计算机学院(CSRankings (2013-2023) 排名 14,QS Rankings (2023) 排名 19)。 计算机学院拥有很多很厉害的老师和学生,他们的研究包括软件工程、编程语言、操作系统等诸多领域。 以下是软件工程、编程语言领域的一些老师,按照姓氏字典序排列,仅供参考: 郝丹胡振江谢涛熊英飞张路张昕
“你为什么还没有回我邮件!”
不好意思,如果一个星期了我都还没回,麻烦再发送一次。

目前的研究项目和方向

以下是我目前主要的研究项目(并不是一个完整的列表)。如果你有兴趣在这些项目上与我进行合作,请联系我!

资源安全的系统编程

程序的资源消耗(比如时间、内存、能源)是计算机科学中的一个重要研究对象,但是它在程序语言理论(比如形式化语义、静态分析、类型系统、程序逻辑)里往往不太受重视。 我对与资源消耗分析相关的项目都很有兴趣,包括程序验证(比如验证现有语言上的现有代码的时间复杂度符合规约)和语言设计(比如使得资源分析更容易、更精确的语言特性)。

在系统编程中,资源消耗分析正变得越来越重要。 编程语言 Rust 的成功说明了现代系统编程需要编程语言提供更强的静态安全保障,比如内存安全和线程安全。 当然,很多现有语言是能够提供多种安全保障的,但往往是通过一些运行时机制(比如垃圾回收),而这些机制会有一定的运行时开销,影响程序性能,这在系统软件中常常不够令人满意。 Rust 语言设计了一个保障内存安全的类型系统,降低了运行时的内存管理开销,从而提高了软件性能。 不过,系统软件的性能并不仅仅与内存管理有关。 我想要提出一个资源安全编程的范式,该范式不但能在静态检查中验证程序的资源消耗符合开发者的预期,而且能够保障程序中没有与资源消耗相关的安全缺陷,比如算法复杂度攻击漏洞和侧信道攻击漏洞。 以下为一些关于资源安全系统编程的中到长期项目:

  • Rust 语言上的资源分析:Rust 中的精确内存模型是否可以帮助提高资源分析的精度和效率?
  • 并发程序的资源分析:Rust 已经可以静态检查一些线程安全问题(如数据竞争),但还存在很多局限,比如不能静态检查是否存在死锁。 我们是否可以在系统编程的类型系统中融入精确的并发模型,并为之设计资源分析的方法?
  • 目标代码资源分析:如何保证编译后的目标代码仍然符合在源代码上分析出的资源消耗情况?更进一步地,如何分析目标代码的细粒度资源消耗,比如时钟周期数? 在这个粒度上,我们需要考虑硬件特性,比如缓存、流水线、分支预测等。
  • 挖掘资源消耗相关安全问题:我们是否可以利用资源消耗分析来挖掘算法复杂度攻击和/或侧信道攻击安全漏洞? 更进一步地,如果发现了潜在漏洞,我们是否可以自动合成一个攻击方案来实际触发该漏洞,以证明漏洞确实存在?

目前我比较倾向尝试的技术路线是自动均摊资源分析(Automatic Amortized Resource Analysis,AARA1)。 当然,我也愿意尝试其它方法,比如递推关系求解(Recurrence Solving)、带大小类型(Sized Types)、阶函数(Ranking Functions)、符号资源分析(Symbolic Resource Analysis)等,毕竟实践是检验真理的唯一标准。

可编程贝叶斯推断

与频率学派的方法(如一般意义上的深度学习)认为模型是一个未知的假设,贝叶斯学习侧重分析能生成观测到的数据的假设的概率分布,从而自然地能对学习到的模型的不确定性进行分析。 贝叶斯学习也有容易融入领域知识、在未知数据上有较好的泛化能力等优点。 概率编程语言(Probabilistic Programming Language,PPL)如 StanPyro 等通过自动化贝叶斯推断使得应用贝叶斯学习更加容易。 这些语言往往通过语言设计来隔离概率模型迭代和贝叶斯推断,并在推断引擎中提供若干种不同的推断算法。

贝叶斯学习的一个主要不足是贝叶斯推断的计算复杂性很高,而且最先进的推断算法也不能在所有概率模型上都有令人满意的效果。 为了使贝叶斯推断在更多的概率模型和更大的数据规模上能够起作用,一些 PPL 减弱了建模和推断之间的隔离,允许用户对一些特性的贝叶斯推断算法进行定制,这种模式被称为可编程推断2。 然而,用户定制推断算法时是比较容易出错的,这些错误会影响贝叶斯推断的收敛性和正确性,甚至很多时候这些错误在开发和模型迭代的过程中难以被察觉。

为了平衡可编程贝叶斯推断的可靠性和灵活性,我希望在概率编程中应用编程语言技术,比如类型系统、静态分析、程序合成等。 通过新的编程抽象和类型系统,我们可以保证推断的可靠性(包括收敛性和正确性),而通过静态分析和程序合成,我们可以为用户提供辅助来自动化推断自定义的过程,从而提高开发效率。 我们的 PLDI 论文可以看作这个研究项目的第一步。

量化程序分析

程序中的随机性可以表现为两方面:外部随机性(比如运行环境中的不确定性)和内部随机性(比如随机化算法)。 正如 Kleene 代数可作为非概率程序的代数程序分析的理论基础3,我希望建立一个适用于概率程序的代数程序分析的理论框架。 为此,我们需要构建一个概率程序的代数语义框架,并以此为基础设计一个通用的概率程序的程序分析求解算法。

非概率程序和概率程序间的一个本质不同是非概率程序的一个运行可以看作一条链,但是概率程序的一个运行需要看作一棵树。 为了说明这一点,我们考虑一个同时支持概率和非确定性的程序模型。 在该模型下,一个非概率程序对应一个可能的运行链的集合,但是一个概率程序需要对应一个概率分布的集合,其中的每个概率分布对应一个运行树,树上的每条从根出发的路径则对应程序中的一条具体的运行链。 我们在 MFPS 论文中基于超图(Hyper-Graphs)给出了上述想法的形式化表示。

抽象解释是一个表达和求解程序分析的强大通用框架。在这个框架中,人们已经设计了多种通用求解策略和收敛技术,比如 Chaotic Iteration、Widening、Narrowing 等。 但是,这些基于迭代的求解算法与概率程序本身的量化特质不太匹配。 假设我们想分析概率循环“$\mathbf{while}~(\mathbf{prob}(3/4))~\{ x = x + 1; \}$”。 变量 $x$ 的期望变化量可以看作是方程 $r = f(r) \equiv (1/4) \cdot 0+(3/4) \cdot (r+1)$ 的最小的解,很容易看出这个解是 $r=3$。 但是,一个基于迭代的求解策略大概会通过一系列近似来逼近 $r$:$\{ f^i(0) \}_{i \in \mathbb{N}}$,该序列并不能在任何有限的迭代次数内收敛。 在数值分析领域中,牛顿法往往是更适用于这种量化特性的方法,所以我希望能够将牛顿程序分析4技术迁移到概率程序的程序分析上。

更进一步地,这个概率程序的代数分析框架从原则上也应该适用于其它的量化性质,比如资源消耗。 我很好奇这一观察是否可以导出一个更通用的量化程序分析框架。 最近的一篇论文5还提出了 Weighted Programming 的概念,进一步从量化数值性质推广到符合某些代数结构的性质。 作为这个通用量化程序分析框架的应用,我们可以在概率分析和资源分析两个社区间进行技术迁移,比如最大后验估计(MAP)跟最坏情况分析(WCA)的数学形式很相近,我希望研究是否可以基于此关系设计新的统计资源分析方法。

其它项目

我对新的方向永远持欢迎的态度,包括跨领域的方向。 以下是一些我有兴趣探索的研究想法,它们通常是短到中期的研究项目。 注意,这个列表并不完整,而且很多想法并不成熟(我甚至预期其中的相当一部分不太能做得出来)。

(以下内容为英文)

静态分析

Library Summarization via Tensor Products

Problem: Library summarization is an effective way to accelerate the analysis of client code. However, information about the client is unknown at the library summarization, preventing complete summarization of the library. A state-of-the-art approach is Conditional Dyck-CFL Reachability Analysis (ConCRA), which targets graph-reachability-like static analyses and uses hypothetical summaries.

Proposal: Lal et al.6 proposed a tensor-product principle: Tensor products with an appropriate detensor operation allow computations to be rearranged in certain ways; for example, they can be used to delay a multiplication in a chain of multiplications. This principle may allow us to generalize, in the summarization framework, Dyck-CFL-reachability-based analyses to algebraic semiring-based analysis.

Follow-up: The library summarization problem can be generalized to partially solving an equation system for a static analysis. Any thoughts on partial evaluation?

NPA-TP for Non-idempotent Semirings

Problem: Esparza et al.4 generalized Newton’s method to a method for finding fixed-points of systems of equations over semirings, leading to a new algorithm to solve interprocedural dataflow analysis. Reps et al.7 developed NPA-TP, which extended Esparza’s framework with an improved algorithm for solving linear-context-free-language (LCFL) sub-problems. However, NPA-TP assumes the underlying abstract domain admits an idempotent semiring; such an assumption rules out interesting analysis domains, especially for numerical properties, e.g., the reaching probability.

Proposal: Esparza’s original framework does support non-idempotent semirings, so it would be a good starting point. The NPA-TP framework features tensor products to solve LCFL sub-problems, and from the perspective of algebras, the principle of tensor products does not require idempotence.

Follow-up: Some recent work shows that quantum computation also needs non-idempotent semirings. Can the idea of NPA-TP be generalized to analyze quantum programs?

Complicated Probability Manipulation

Problem: In many programs, the manipulation of probability is very complicated and even manual analysis of their correctness is difficult. Consider the problem below:

x = p;
while (prob(0.5)) {
  x = 2 * x;
  if (x >= 1) {
    x = x - 1;
  }
}

We want to verify that at the end of the loop, the probability of the event $x \ge \frac{1}{2}$ is exactly $p$.

Proposal: Probability-generating functions provide a succinct way to describe probability distributions of discrete random variables. We might try to derive the probability-generating function of a probabilistic program to reason about the resulting distribution of the program. A recent paper8 is on this direction.

Follow-up: There is a connection between derivatives of the probability-generating function of a random variable $X$ and the moments of $X$. Can we use the fact to perform moment analysis?

Fine-grained Heap Abstraction via Regular Patterns

Problem: Static analysis of heap-manipulation programs often involves heap sensitivity. In the simplest case, all memory allocations with the same program location are treated as a single allocation (thus in a context-insensitive way). Advanced techniques include three-value-logic for shape analysis, $k$-CFA, $m$-CFA9, etc. However, they seem insufficient when we want to analyze recursive programs. (Imagine that in functional programming, iterating over a list is usually implemented as a recursive function.)

Proposal: We can treat the set of all call-strings as a language, then different strategies for handling sensitivity are essentially different ways of defining equivalence classes on the language. A presumably good proposal is to use regular patterns to classify equivalence classes. For example, $(ff)^*$ indicates calling a function $f$ for an even number of times, $f(ff)^*$ for an odd number.

Follow-up: In fact, this approach should generalize to all sensitivities that use call strings. Is it meaningful to develop a general framework with regular-pattern-sensitivity?

形式化语义

Combination of Continuous Distributions and Nondeterminism-first

Problem: Nondeterminism-first means that we resolve nondeterminism prior to program inputs when defining denotational semantics. For example, suppose that a deterministic function has the signature $A \to B$, then a standard resolution of nondeterminism gives us $A \to \wp(B)$, but nondeterminism-first suggests $\wp(A \to B)$. Nondeterminism-first can be useful for e.g., compile-time nondeterminism. A recent study proposed a denotational semantics for probabilistic programs that combines discrete distributions (on a countable state space) and nondeterminism-first. However, it remains open if the semantics can be extended to support continuous distributions.

Proposal: In fact, I do not have any ideas yet.

Follow-up: What about a computational theory for such a combination?

Combination of Probability and Message-passing Concurrency

Problem: The common treatment of a probabilistic flip in the semantics is to “split” the current program configuration into two, one for the “world” where the flip shows heads and the other for tails. When we need to deal with multiple concurrent processes, such a treatment means a local flip in a process results in duplicating all other processes. Such a non-local (thus non-compositional) behavior has been shown to be problematic for proving soundness of formal methods (e.g., type systems, which are usually compositional).

Proposal: The result of a probabilistic flip should remain as local as possible. We have recently developed an operational semantics with the desirable locality, but I feel that a more algebraic representation is better. For example, we might want to rearrange the operational semantics to reduction rules and congruence rules. Furthermore, we should prove an equivalence result to the ordinary probabilistic semantics (e.g., Markov chains).

Follow-up: I can always imagine that adding nondeterminism causes a lot of troubles.

Building a Framework for Nondeterminism-as-refinement

Problem: Nondeterminism is often referred to as the basis of abstraction and refinement in the setting of stepwise developement10. However, such a pattern has not been popular in modern programming languages. What is the main obstable for developing such a framework? Also, people have developed many kinds of semantics for nondeterminism. Which semantics should be the most suitable one for refinement-based programming and reasoning?

Proposal: I guess this has something to do with relational Hoare Logics11. At least they provide a way to use nondeterminism in a formal framework of proving program properties.

Follow-up: How to devise a language design for it?

类型系统

Safe Interaction between Typed Domain Specific Languages

Problem: Consider we have a typed programming language that is suitable for developing embedded Domain Specific Languages (eDSLs). Every eDSL can directly use the base type system from the host language, but it can also have its own advanced domain-specific type system. Languages such as MetaOCaml have already supported such a mechanism, but the interaction between the host language and the eDSL, or maybe even between different eDSLs, is not very convenient yet. It would be nice to have a simple and safe interaction scheme among eDSLs on a same host language.

Proposal: In fact, I do not have any ideas yet.

Follow-up: What else should we have for such a flexible eDSL framework? For example, we might want to consider multi-stage compilation, debugger, mixed paradigm, etc.

Lightweight Shape Check for Array Programming

Problem: Array programming (or tensor programming) is pervasive nowadays because of machine learning. Many machine-learning frameworks lack the ability to statically check tensor shapes are always consistent during program execution. Approaches based on dependent/refinement/indexed types all seem too heavy to become practical.

Proposal: In many (really?) cases, when the input of an array program is fixed, the shapes of all intermediate arrays are also fixed. So we can perform a static shape check after the input is given, but before we execute the program, by propagating the concrete shape information from the given input.

Follow-up: Is it possible to automatically learn the shape-related effects of library functions (e.g., broadcast_tensor)?

Integration of Refinement Types and Separation Logic

Problem: Recently, people have developed verification systems, e.g., CN12 and RefinedC13, which integrate refinement types and separtion logic to reason about low-level programs. In those systems, refinements seem to still encode purely functional properties (really?). How about enabling type refinements to be separation-logic propositions? To that end, such refined types are not structural any more and we need to work with substructural refinemend types. Does the integration make sense?

Proposal: It seems that we can start from linear refinement types.

Follow-up: Linear typing and separation logic share a lot of similarities. Are both rooted back in linear logic? If not, what is the fundamental difference?

Liquid-type-style Dijkstra Monads

Problem: Dijkstra monads14 were originally proposed to automate the verification-condition-generation (VCG) routine for analyzing effectful higher-order programs. They later form the basis of F*, a proof-oriented programming language15. One feature of F* is that it supports proof-irrelevant refinement types. Liquid types16 provide another method of balancing between automatic type inference and dependent typing. One main idea of liquid types is to separately design a language for specification. Can we combine Dijkstra monads and liquid types? What are the benefits—if there are—to do this?

Proposal: So the system is basically a comination of liquid-style language design and an F*-style type inference.

Follow-up: Dijkstra monads support multi-monadic effects in a systematic way. This means we might have a method to extend our ICFP paper to include the value interpretation as in the language itself.

资源分析

Fraction Bounds for Expected Cost Analysis

Problem: Most of current resource-analysis techniques derive linear, polynomial, or exponential bounds. However, when analyzing probabilistic programs, we often encounter bounds that involve fractions. For example, the simple loop while (prob(p)) tick(1); has an expected cost of $\frac{p}{1-p}$, where $p$ is a program variable that denotes a non-trivial probability.

Proposal: In many cases, a fraction bound can be expressed as a polynomial over another polynomial. So it should be possible to extend current template-based resource-analysis techniques (e.g., AARA) that derive polynomial bounds, by using a template for the denominator to reduce fraction-bound inference to polynomial-bound inference.

Follow-up: A random thought: how can we apply such resource-analysis technique to Bayesian inference (like a recent paper by Beutner et al.17)?

AARA for Probabilistic Functional Programs with Non-monotone Resources

Problem: Our ICFP paper presents an extension of AARA that infers upper bounds on the expected cost of probabilistic functional programs with monotone resources (such as time). In general, combining probability and non-monotone resources (such as memory) is unreasonably complex18. Applying optional stopping theorems, people have successfully developed techniques for analyzing arithmetic programs. It would be interesting to see if the whole methodology applies to functional programming, where we have inductive data structures (that can hold potential) instead of numbers.

Proposal: One version of optional stopping theorems states that the expected change in one evaluation step should be “bounded.” This should intuitively hold for functional programming (I mean, in most cases) because one step should change the size of a data structure by at most one (consider the case of cons). By constructing a suitable Markov chain, we might be able to reason about probabilistic functional programs with non-monotone resources.

Follow-up: Optional stopping theorems always talk about “expected change” and “expected termination time.” Why them?!

Newtonian Resource Analysis

Problem: Apply the Newtonian Program Analysis (NPA) framework4 and its extension7 to carray out resource analysis. Existing work has shown the possibility to perform recurrence-based analysis19. How about other kinds of resource analysis, like AARA?

Proposal: Because amortized analysis is naturally two-vocabulary, it seems possible to recast AARA as a two-vocabulary abstract domain. The gap is that AARA is constraint-based, which differs from the general NPA framework.

Follow-up: NPA basically provides a framework for analyzing non-linear-recursive programs by iteratively analyzing linear-recursive programs. Can we combine this idea to iteratively use AARA to solve linear recursion?

Worst-case Lower-bound Resource Analysis

Problem: Most work on resource analysis focuses on worst-case upper bounds, but in practice people also want to know worst-case lower bounds, i.e., whether there exists a realizable execution path leading to the bound. This could usually be done by testing techniques for worst-case analysis, e.g., fuzzing20. Recent advances on incorrectness logic21 and coverage typing22 show the power of suhc realizability analysis. We want to follow those lines of work to build type systems or program logics to reason about worst-case lower bounds.

Proposal: From the perspective of incorrectness logic, one can extend separation logic with time credits. From the perspective of coverage typing, one can extend liquid resource types.

Follow-up: Is it possible to integrate such deductive analysis with fuzzing-based worst-case analysis?

概率编程

Domain-specific Procedural Design

Problem: Daniel Ritchie suggested generative probabilistic programming for procedural modeling and design (the use of random programs to generate visual content with respect to aesthetic or functional constraints). Such an approach has been rediscovered in several individual developments, such as Scenic23 and Picture24. So instead of separate developments, we want to develop a framework to ease such domain-specific procedural design.

Proposal: This has something to do with the eDSL framework.

Follow-up: It might be interesting to see how such static procedural design evolves to dynamic procedural design (e.g., synthesis of an environment). Another direction is interactive refinement (e.g., incorporating feedbacks from users) of the generated designs.

Language Design for Sound Involutive MCMC

Problem: A recent paper by Cusumano-Towner et al.25 studies how to ease the burden of implementing involutive MCMC by combining probabilistic programming and differentiable programming. It still remains a challenge (emm, you have to double check) to statically verify the correctness of a concrete implementation in their framework.

Proposal: I would try to combine type systems for sound programmable inference and sound differentiable programming.

Follow-up: I am thinking of The Next XXX MCMC Algorithms.

Quantum Probability and Bayesian Inference

Problem: Quantum physics uses a form of complex probability. People have been thinking of it as a serious probability theory (see this and this). There are even quantum analogs of Bayesian inference (one and the other). Does it make sense to incorporate some of those ideas in current probabilistic programming systems?

Proposal: I still have to learn quantum physics (emm, not really).

Follow-up: Some people are trying to add quantum features to standard Bayesian models (check out this).

程序合成

Interface Synthesis for Database Tables

Problem: One central function of low-code programming platforms is to automatically generate usable interface for manipulating database tables. In an application, the developers might want to customize a specific way to organize the interface, and they want to reuse the customization across the application.

Proposal: The customization can be thought as a functor that takes a database-table module as its input and outputs an inference module for that table. For low-code programming, it would be useful to have a mechanism where the developers customize a table interactively and the platform automatically synthesize the code of the customization functor.

Follow-up: Low-code programming involves many UI-related customization. Is there a more general principle? For example, it might be interesting to investigate Natural Programming.

Resource-guided Synthesis and Implicit Computational Complexity

Problem: Recently, resource-guided synthesis and algorithm synthesis have received considerable attention26 27. We also had published a related PLDI paper. Those approaches can be categorized into two sorts: one develops a complex type system of program logic to enforce resource guarantees, the other proposes algorithmic templates that ensure resource guarantees. The latter is somewhat related to Implicit Computational Complexity (ICC), which characterizes algorithms by constraints on the way in which they are constructed. In other words, an ICC research usually provides a non-standard programming language, in which every legal program is guaranteed to have certain complexity. Can we generalize the template-based approach to ICC-based approach?

Proposal: A starting point could be non-size-increasing computaion28.

Follow-up: ICC seems to be not so fine-grained, e.g., usually researchers focus on whether the complexity is polynomial or not. How to make them finer-grained? For example, would it be possible to develop an ICC class for $O(n \log n)$ algorithms?

程序验证

Verifying Time/Memory Complexities in VST

Problem: Verified Software Toolchain (VST) is a set of verified tools that formally verify the functional correctness of C programs using Hoare logic and separation logic. I wonder if it is also convenient to verify resource-usage properties of C programs, like their time or memory complexities.

Proposal: It has been shown that separation logic naturally supports resource verification based on time credits29. So conceptually it should be possible to have that in VST.

Follow-up: Can we develop some general reasoning libraries for resource verification?

Backward Proving in Coq

Problem: Coq proofs are organized in a forward, tactic-based manner, which is not very readable. In contrast, Isabelle (and some other theorem provers) provides a backward mode, where the intermediate goals are stated explicitly, so that improves readability. Is it possible to use a backward pattern in Coq proofs? If not, would it be possible to have a backward-proof DSL that can be translated to Coq?

Proposal: Isabelle’s Isar might be a good starting point.

Follow-up: What is the best proof interface for system programmers?

Refinement-based System Programming

Problem: Many verification projects (e.g., seL4) start from a high-level specification implemented in a functional language (e.g., Haskell) and then prove a concrete implementation in a system programming language (e.g., C) refine the specification. From the perspective of software engineering, this suggests another way of system programming: first implement a functional specification and then (iteratively) refine it to build a concrete low-level implementation.

Proposal: Build a language where the high-level and low-level languages can interoperate seamlessly, e.g. Haskell and C. Existing solutions are somehow quite complex, in the sense that they want to interoperate with a realistic C compiler directly. However, it would be nice enough for the development process if the C part is just supported partially, but with better support, e.g., to be equipped with an interpreter.

Follow-up: What is the best practice for multi-language (i.e., multilingual) software engineering?


  1. Jan Hoffmann and Steffen Jost. Two Decades of Automatic Amortized Resource Analysis. Math. Struct. Comput. Sci. (2022). DOI ↩︎

  2. Vikash K. Mansinghka, Ulrich Schaechtle, Shivam Handa, Alexey Radul, Yutian Chen, and Martin Rinard. Probabilistic Programming with Programmable Inference. Prog. Lang. Design and Impl. (2018). DOI ↩︎

  3. Zachary Kincaid, Thomas Reps, and John Cyphert. Algebraic Program Analysis. DOI ↩︎

  4. Javier Esparza, Stefan Kiefer, and Michael Luttenberger. Newtonian Program Analysis. J. ACM (2010). DOI ↩︎ ↩︎ ↩︎

  5. Kevin Batz, Adrian Gallus, Benjamin Lucien Kaminski, Joost-Pieter Katoen, and Tobias Winkler. Weighted Programming: A Programming Paradigm for Specifying Mathematical Models. Object-Oriented Prog., Syst., Lang., and Applications (2022). DOI ↩︎

  6. Akash Lal, Tayssir Touili, Nicholas Kidd, and Thomas Reps. Interprocedural Analysis of Concurrent Programs Under a Context Bound. Tools and Algor. for the Constr. and Anal. of Syst. (2008). DOI ↩︎

  7. Thomas Reps, Emma Turetsky, and Prathmesh Prabhu. Newtonian Program Analysis via Tensor Product. Princ. of Prog. Lang. (2016). DOI ↩︎ ↩︎

  8. Mingshuai Chen, Joost-Pieter Katoen, Lutz Klinkenberg, and Tobias Winkler. Does a Program Yield the Right Distribution?. Computer Aided Verif. (2022). DOI ↩︎

  9. Matthew Might, Yannis Smaragdakis, and David Van Horn. Resolving and Exploiting the $k$-CFA Paradox: Illuminating Functional vs. Object-Oriented Program Analysis. Prog. Lang. Design and Impl. (2010). DOI ↩︎

  10. Edsger W. Dijkstra. A Discipline of Programming. Prentice Hall PTR (1997). DOI ↩︎

  11. Nick Benton. Simple Relational Correctness Proofs for Static Analyses and Program Transformations. Princ. of Prog. Lang. (2004). DOI ↩︎

  12. Christopher Pulte, Dhruv C. Makwana, Thomas Sewell, Kayvan Memarian, Peter Sewell, and Neel Krishnaswami. CN: Verifying Systems C Code with Separation-Logic Refinement Types. Princ. of Prog. Lang. (2023). DOI ↩︎

  13. Michael Sammler, Rodolphe Lepigre, Robbert Krebbers, Kayvan Memarian, Derek Dreyer, and Deepak Garg. RefinedC: Automating the Foundational Verification of C Code with Refined Ownership Types. Prog. Lang. Design and Impl. (2021). DOI ↩︎

  14. Nikhil Swamy, Joel Weinberger, Cole Schlesinger, Juan Chen, and Benjamin Livshits. Verifying Higher-order Programs with the Dijkstra Monad. Prog. Lang. Design and Impl. (2013). DOI ↩︎

  15. Nikhil Swamy, Cătălin Hriţcu, Chantal Keller, Aseem Rastogi, Antoine Delignat-Lavaud, Simon Forest, Karthikeyan Bhargavan, Cédric Fournet, Pierre-Yves Strub, Markulf Kohlweiss, Jean-Karim Zinzindohoue, and Santiago Zanella-Béguelin. Dependent Types and Multi-monadic Effects in F*. Princ. of Prog. Lang. (2016). DOI ↩︎

  16. Patrick M. Rondon, Ming Kawaguci, and Ranjit Jhala. Liquid Types. Prog. Lang. Design. and Impl. (2008). DOI ↩︎

  17. Raven Beutner, Luke Ong, and Fabian Zaiser. Guaranteed Bounds for Posterior Inference in Universal Probabilistic Programming. Prog. Lang. Design and Impl. (2022). DOI ↩︎

  18. Marcel Hark, Benjamin Lucien Kaminski, Jürgen Giesl, and Joost-Pieter Katoen. Aiming Low Is Harder: Induction for Lower Bounds in Probabilistic Program Verification. Princ. of Prog. Lang. (2020). DOI ↩︎

  19. Zachary Kincaid, Jason Breck, Ashkan Forouhi Boroujeni, and Thomas Reps. Compositional Recurrence Analysis Revisited. Prog. Lang. Design and Impl. (2017). DOI ↩︎

  20. Jiayi Wei, Jia Chen, Yu Feng, Kostas Ferles, and Isil Dillig. Singularity: Pattern Fuzzing for Worst Case Complexity. Found. of Softw. Eng. (2018). DOI ↩︎

  21. Peter W. O’Hearn. Incorrectness Logic. Princ. of Prog. Lang. (2020). DOI ↩︎

  22. Zhe Zhou, Ashish Mishra, Benjamin Delaware, and Suresh Jagannathan. Covering All the Bases: Type-Based Verification of Test Input Generators. Prog. Lang. Design and Impl. (2023). DOI ↩︎

  23. Daniel J. Fremont, Tommaso Dreossi, Shromona Ghosh, Xiangyu Yue, Alberto L. Sangiovanni-Vincentelli, and Sanjit A. Seshia. Scenic: A Language for Scenario Specification and Scene Generation. Prog. Lang. Design and Impl. (2019). DOI ↩︎

  24. Tejas D. Kulkarni, Pushmeet Kohli, Joshua B. Tenenbaum, and Vikash Mansinghka. Picture: A Probabilistic Programming Language for Scene Perception. Comp. Vision and Pattern Recognition (2015). DOI ↩︎

  25. Marco Cusumano-Towner, Alexander K. Lew, and Vikash K. Mansinghka. Automating Involutive MCMC using Probabilistic and Differentiable Programming. arXiv ↩︎

  26. Qinheping Hu, John Cyphert, Loris D’Antoni, and Thomas Reps. Synthesis with Asymptotic Resource Bounds. Computer Aided Verif. (2021). DOI ↩︎

  27. Yican Sun, Xuanyu Peng, and Yingfei Xiong. Synthesizing Efficient Memoization Algorithms. Object-Oriented Prog., Syst., Lang., and Applications (2023). ↩︎

  28. Martin Hofmann. Linear types and non-size-increasing polynomial time computation. Logic in Computer Science (1999). DOI ↩︎

  29. Arthur Charguéraud and François Pottier. Machine-Checked Verification of the Correctness and Amortized Complexity of an Efficient Union-Find Implementation. Interactive Theorem Proving (2015). DOI ↩︎