Skip to content

Statistics Library Blog - #43

Merged
keyboardDrummer merged 18 commits into
dafny-lang:mainfrom
Bhaveshb-bytes:main
Dec 10, 2025
Merged

Statistics Library Blog#43
keyboardDrummer merged 18 commits into
dafny-lang:mainfrom
Bhaveshb-bytes:main

Conversation

@Bhaveshb-bytes

@Bhaveshb-bytes Bhaveshb-bytes commented Dec 5, 2025

Copy link
Copy Markdown
Contributor

This serves as the PR for the blog post for official Statistics Library. @robin-aws Please let us know if there are any changes needed on the content or the CI side

@robin-aws robin-aws left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very nice work on this, very readable and does a great job motivating the contribution and describing the journey to the final product.

Comment thread _posts/2025-12-01-statistics-library.markdown Outdated

## Order statistics: median and range

Beyond mean and variance, a statistics library should also provide basic order statistics such as median and range. Since Dafny’s standard collections already provide a merge sort ([MergeSortBy](https://github.com/dafny-lang/dafny/blob/68fb5ed04006b9be9601695d3d74687bbe3800b4/Source/DafnyStandardLibraries/src/Std/Collections/Seq.dfy#L1041)), we reuse it rather than re–implement ordering ourselves . This is exactly the kind of situation where strong libraries make a difference: instead of proving sorting correctness again, we can build directly on a verified component and focus on the statistical logic itself.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

❤️

}
{% endhighlight %}

You remember our first line, What looks simple in code often becomes interesting the moment you try to prove it. This is one of the cases where we faced such an issue. Our FrequencyTable function seemed simple: take a sequence and build a map counting occurrences.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
You remember our first line, What looks simple in code often becomes interesting the moment you try to prove it. This is one of the cases where we faced such an issue. Our FrequencyTable function seemed simple: take a sequence and build a map counting occurrences.
You remember our first line: "What looks simple in code often becomes interesting the moment you try to prove it." This is one of the cases where we faced such an issue. Our FrequencyTable function seemed simple: take a sequence and build a map counting occurrences.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Made the required changes

{% endhighlight %}

You remember our first line, What looks simple in code often becomes interesting the moment you try to prove it. This is one of the cases where we faced such an issue. Our FrequencyTable function seemed simple: take a sequence and build a map counting occurrences.
Now , Formally, we wanted Dafny to verify:

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"Formally" as in previously?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

'Formally' was a bit ambiguous there. I have rephrased the sentence to: 'To ensure correctness, we formally had to verify that:' to make the intent clearer.

{% endhighlight %}

This design has a few advantages:
- It runs in *O(n)* time: one pass to build the frequency map and one pass to find the best.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a bit too strong a claim, for two different reasons:

  1. Building the frequency table actually takes quadratic time because each map update such as m[key := m[key] + 1] have to make a new copy of the map (since Dafny maps are immutable). This could be optimized in the Dafny runtimes but hasn't been yet.
  2. Each map lookup is not necessarily constant time in practice, because the runtimes generally use something like a HashMap, which is only going to be constant time on average, but can be linear in the worst case.

The first point could hypothetically be addressed by using a MutableMap from the Concurrent standard library, but the second point is a pretty fundamental data structures limit.

You definitely don't need to address this in the library itself, but you may want to add a bit of this detail, and definitely soften this runtime claim. It's still definitely true that the original version was quite a bit worse than quadratic :)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with the points. Writing Linear time is sort of a tall claim and hence, I have made the required change here by telling how our approach is better.

Comment thread _posts/2025-12-01-statistics-library.markdown Outdated
They also show how simple it is to work with the module: you can call Mean, Median, VariancePopulation, Mode, and the rest just like any normal function without worrying about the underlying proofs. In that sense, the tests double as a quick “how to use this library” guide while demonstrating its correctness on real data.


## Acknowledgments

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider swapping the last two sections, I think it flows a bit better to end with acknowledgements

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done :)

layout: post
title: "A Verified Statistics Library for Dafny"
author: Bhavesh Bhatia and Tanay Mathur
date: 2025-12-01 09:00:00 +0000

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just FYI since it came up earlier, this date is only used to allow blog posts to be merged that should not be actually published until a future date. When this is merged, as long as this date is in the past the new post will appear with the correct actual publication date. In other words this value is just fine. :)

Because our helper `SumSquaredDifferences` is proven non-negative, Dafny automatically verifies that `VariancePopulation` and `VarianceSample` are also non-negative. Note that `VarianceSample` requires `|s| > 1`, because dividing by N - 1 where N is 1 would cause a division by zero!

### 5. Standard Deviation
Finally, we arrive at Standard Deviation, which is the square root of the Variance. Since Dafny doesn't have a built-in square root, we define an `extern` function in a separate module.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Dafny doesn't have a built-in square root

Actually it does now! A new floating point type was added that supports square root: https://dafny.org/dafny/DafnyRef/DafnyRef#5236-mathematical-functions

You can just rephrase this to say it didn't have this at the time, and perhaps mention in the future work section that we could refactor the code to use this new type, and hence make it no longer target-specific.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah! Thank you for letting us know. I have added the point as you asked me to!

Tanay261 and others added 5 commits December 8, 2025 18:45
Co-authored-by: Robin Salkeld <salkeldr@amazon.com>
Co-authored-by: Robin Salkeld <salkeldr@amazon.com>
Reworded sections for clarity and improved flow. Added acknowledgments section back to the document.
Corrected phrasing for clarity regarding Dafny's capabilities.
@keyboardDrummer
keyboardDrummer merged commit 15b9ed0 into dafny-lang:main Dec 10, 2025
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants