Zulip Chat Archive

Stream: CSLib

Topic: RMQ


Li Xuanji (Feb 23 2026 at 05:18):

Hello, I've formalized a data structure (commonly called a "sparse table") that solves the RMQ problem, which is to find the minimum value in a sub-array of an array. I wonder if this is suitable for CSLib.

Generally, preprocessing is needed on the input data; a data structure solves RMQ in <p, q> if the preprocessing time is p and the query time is q. Wikipedia has a summary of the different approaches.

  • Naive approach (no preprocessing): <O(1), O(n)>
  • Naively precompute all answers: <O(n^3), O(1)>
  • Precompute all answers using dynamic programming: <O(n^2), O(1)>
  • Sparse table (this formalization): <O(n log n), O(1)>
  • Optimal solution: <O(n), O(1)>, e.g. Fischer and Heun

There also exist easier solutions in <O(n log log n), O(1)> and <O(1), O(log n)> (both mentioned in the Wikipedia article), which could be intermediate targets to formalize before the optimal ones.

My choice for stating that a data structure solves RMQ was to package the data structure, functions, and proofs into a structure, and use TimeM annotations for the time complexity:

/-
A structure for stating that `α` and some associated (TimeM-annotated) functions is a solution to the RMQ problem.
- `make` : preprocess an array of values `a`, returning an `α`
- `query` : query `α` for the minimum value in a subarray of `a`
- `correct` : the result is the same as the naive implementation
- `make_time`, `query_time` : the time complexity of `make` and `query`, as a function of `|a|`
- `make_time_bound`, `query_time_bound` : proofs of the time complexity bounds
-/
class RMQSolution (α : Type) where
  make : Array   TimeM α
  query : α      TimeM 
  correct (a : Array ) (l r : ) (h : l  r) (hr : r < a.size) :
    (query make a l r) = rmqNaive a l r
  make_time :   
  make_time_bound :  a : Array , (make a).time  make_time a.size
  query_time :   
  query_time_bound :  a : Array ,  l r : , (query make a l r).time  query_time a.size

instance : RMQSolution SparseTable where
  make := SparseTable.make
  query := SparseTable.query
  correct := correct
  make_time n := n * Nat.log 2 n
  make_time_bound := SparseTable.make_time
  query_time _ := 1
  query_time_bound := fun _ l r => by simp [SparseTable.query_time]

Shreyas Srinivas (Feb 23 2026 at 10:41):

This is the kind of formalisation I would prefer to see in Prog instead of TimeM, because it starts to reach the threshold where review complexity goes up since you are using custom tick sizes

Shreyas Srinivas (Feb 23 2026 at 10:42):

And this is just the beginning.


Last updated: Feb 28 2026 at 14:05 UTC