### Install Pragmastat
Source: https://pragmastat.dev/py
Install the library using pip.
```bash
pip install pragmastat==14.0.1
```
--------------------------------
### Install Pragmastat via Go
Source: https://pragmastat.dev/go
Use the go get command to add the specific version of the library to your project.
```bash
go get github.com/AndreyAkinshin/pragmastat/go/v14@v14.0.1
```
--------------------------------
### Sample Usage Examples
Source: https://pragmastat.dev/sample
Basic usage examples for selecting elements from a list and the identity case where selecting all elements returns the original order.
```text
Rng("demo-sample").Sample([1, 2, 3, 4, 5], 3)
```
```text
r.Sample(x, n) = x
```
--------------------------------
### Install Pragmastat from GitHub
Source: https://pragmastat.dev/r
Use the remotes package to install the Pragmastat library from the specified GitHub repository and subdirectory.
```R
install.packages("remotes") # If 'remotes' is not installed
remotes::install_github("AndreyAkinshin/pragmastat",
subdir = "r/pragmastat", ref = "v14.0.1")
library(pragmastat)
```
--------------------------------
### Pragmastat Library Usage Demonstration
Source: https://pragmastat.dev/go
A complete example demonstrating one-sample and two-sample statistics, confirmatory comparisons, random number generation, and distribution sampling. Helper functions are used to handle errors during measurement and sample creation.
```go
package main
import (
"fmt"
"log"
pragmastat "github.com/AndreyAkinshin/pragmastat/go/v14"
)
func mustM(val pragmastat.Measurement, err error) pragmastat.Measurement {
if err != nil {
log.Fatal(err)
}
return val
}
func mustB(val pragmastat.Bounds, err error) pragmastat.Bounds {
if err != nil {
log.Fatal(err)
}
return val
}
func mustS(val *pragmastat.Sample, err error) *pragmastat.Sample {
if err != nil {
log.Fatal(err)
}
return val
}
func mustT(val *pragmastat.Threshold, err error) *pragmastat.Threshold {
if err != nil {
log.Fatal(err)
}
return val
}
func mustP(val []pragmastat.Projection, err error) []pragmastat.Projection {
if err != nil {
log.Fatal(err)
}
return val
}
func main() {
// --- One-Sample ---
xVals := make([]float64, 200)
for i := range xVals {
xVals[i] = float64(i + 1)
}
x := mustS(pragmastat.NewSample(xVals))
fmt.Println(mustM(x.Center()).Value) // 100.5
fmt.Println(mustB(x.CenterBounds(1e-3))) // [86;115]
fmt.Println(mustM(x.Spread()).Value) // 59
fmt.Println(mustB(x.SpreadBoundsWithSeed(1e-3, "demo"))) // [44;87]
// --- Two-Sample ---
sxVals := make([]float64, 200)
for i := range sxVals {
sxVals[i] = float64(i + 1)
}
syVals := make([]float64, 200)
for i := range syVals {
syVals[i] = float64(i + 101)
}
sx := mustS(pragmastat.NewSample(sxVals))
sy := mustS(pragmastat.NewSample(syVals))
fmt.Println(mustM(sx.Shift(sy)).Value) // -100
fmt.Println(mustB(sx.ShiftBounds(sy, 1e-3))) // [-120;-80]
fmt.Println(mustM(sx.Ratio(sy)).Value) // 0.5008354224706336
fmt.Println(mustB(sx.RatioBounds(sy, 1e-3))) // [0.4066666666666668;0.5958333333333332]
fmt.Println(mustM(sx.Disparity(sy)).Value) // -1.694915254237288
fmt.Println(mustB(sx.DisparityBoundsWithSeed(sy, 1e-3, "demo"))) // [-3.1025641025641026;-0.8494623655913979]
// --- Confirmatory Comparison ---
th1 := mustT(pragmastat.NewThreshold(pragmastat.MetricCenter, pragmastat.NewNumberMeasurement(50), 1e-3))
proj1 := mustP(pragmastat.Compare1(sx, []*pragmastat.Threshold{th1}))
fmt.Println(proj1[0].Verdict) // greater
th2 := mustT(pragmastat.NewThreshold(pragmastat.MetricShift, pragmastat.NewNumberMeasurement(0), 1e-3))
proj2 := mustP(pragmastat.Compare2(sx, sy, []*pragmastat.Threshold{th2}))
fmt.Println(proj2[0].Verdict) // less
// --- Randomization ---
rng := pragmastat.NewRngFromString("demo-uniform")
fmt.Println(rng.UniformFloat64()) // 0.2640554428629759
fmt.Println(rng.UniformFloat64()) // 0.9348534835582796
rng = pragmastat.NewRngFromString("demo-uniform-int")
fmt.Println(rng.UniformInt64(0, 100)) // 41
rng = pragmastat.NewRngFromString("demo-sample")
fmt.Println(pragmastat.RngSample(rng, []float64{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, 3)) // [3 8 9]
rng = pragmastat.NewRngFromString("demo-resample")
fmt.Println(pragmastat.RngResample(rng, []float64{1, 2, 3, 4, 5}, 7)) // [3 1 3 2 4 1 2]
rng = pragmastat.NewRngFromString("demo-shuffle")
fmt.Println(pragmastat.RngShuffle(rng, []float64{1, 2, 3, 4, 5})) // [4 2 3 5 1]
// --- Distributions ---
rng = pragmastat.NewRngFromString("demo-dist-additive")
fmt.Println(pragmastat.NewAdditive(0, 1).Sample(rng)) // 0.1741044867956819
rng = pragmastat.NewRngFromString("demo-dist-multiplic")
fmt.Println(pragmastat.NewMultiplic(0, 1).Sample(rng)) // 1.1273244602673853
rng = pragmastat.NewRngFromString("demo-dist-exp")
fmt.Println(pragmastat.NewExp(1).Sample(rng)) // 0.6589065267276553
rng = pragmastat.NewRngFromString("demo-dist-power")
fmt.Println(pragmastat.NewPower(1, 2).Sample(rng)) // 1.023677535537084
rng = pragmastat.NewRngFromString("demo-dist-uniform")
fmt.Println(pragmastat.NewUniform(0, 10).Sample(rng)) // 6.54043657816832
}
```
--------------------------------
### Install Pragmastat via Cargo
Source: https://pragmastat.dev/rs
Add the library to your project using the cargo command-line tool.
```bash
cargo add pragmastat@14.0.1
```
--------------------------------
### Install Pragmastat via npm
Source: https://pragmastat.dev/ts
Use this command to add the library to your project dependencies.
```bash
npm i pragmastat@14.0.1
```
--------------------------------
### Pragmastat Library Demonstration
Source: https://pragmastat.dev/rs
A comprehensive example covering one-sample and two-sample statistics, confirmatory comparisons, random number generation, probability distributions, and unit system management.
```rust
use pragmastat::distributions::{Additive, Distribution, Exp, Multiplic, Power, Uniform};
use pragmastat::*;
fn main() {
// --- One-Sample (Sample-based API) ---
let x = Sample::new((1..=200).map(|i| i as f64).collect()).unwrap();
println!("{}", center(&x).unwrap().value); // 100.5
let bounds = center_bounds(&x, 1e-3).unwrap();
println!("{{lower: {}, upper: {}}}", bounds.lower, bounds.upper); // {lower: 86, upper: 115}
println!("{}", spread(&x).unwrap().value); // 59
let bounds = spread_bounds_with_seed(&x, 1e-3, "demo").unwrap();
println!("{{lower: {}, upper: {}}}", bounds.lower, bounds.upper); // {lower: 44, upper: 87}
// --- Two-Sample (Sample-based API) ---
let x = Sample::new((1..=200).map(|i| i as f64).collect()).unwrap();
let y = Sample::new((101..=300).map(|i| i as f64).collect()).unwrap();
println!("{}", shift(&x, &y).unwrap().value); // -100
let bounds = shift_bounds(&x, &y, 1e-3).unwrap();
println!("{{lower: {}, upper: {}}}", bounds.lower, bounds.upper); // {lower: -120, upper: -80}
println!("{}", ratio(&x, &y).unwrap().value); // 0.5008354224706334
let bounds = ratio_bounds(&x, &y, 1e-3).unwrap();
println!("{{lower: {}, upper: {}}}", bounds.lower, bounds.upper); // {lower: 0.4066666666666668, upper: 0.5958333333333332}
println!("{}", disparity(&x, &y).unwrap().value); // -1.694915254237288
let bounds = disparity_bounds_with_seed(&x, &y, 1e-3, "demo").unwrap();
println!("{{lower: {}, upper: {}}}", bounds.lower, bounds.upper); // {lower: -3.1025641025641026, upper: -0.8494623655913979}
// --- Confirmatory Comparison ---
let th = Threshold::new(Metric::Center, Measurement::number(50.0), 1e-3).unwrap();
println!("{}", compare1(&x, &[th]).unwrap()[0].verdict().as_str()); // greater
let th = Threshold::new(Metric::Shift, Measurement::number(0.0), 1e-3).unwrap();
println!("{}", compare2(&x, &y, &[th]).unwrap()[0].verdict().as_str()); // less
// --- Randomization ---
let mut rng = Rng::from_string("demo-uniform");
println!("{}", rng.uniform_f64()); // 0.2640554428629759
println!("{}", rng.uniform_f64()); // 0.9348534835582796
let mut rng = Rng::from_string("demo-uniform-int");
println!("{}", rng.uniform_i64(0, 100)); // 41
let mut rng = Rng::from_string("demo-sample");
println!(
"{:?}",
rng.sample(&[0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0], 3)
); // [3.0, 8.0, 9.0]
let mut rng = Rng::from_string("demo-resample");
println!("{:?}", rng.resample(&[1.0, 2.0, 3.0, 4.0, 5.0], 7)); // [3.0, 1.0, 3.0, 2.0, 4.0, 1.0, 2.0]
let mut rng = Rng::from_string("demo-shuffle");
println!("{:?}", rng.shuffle(&[1.0, 2.0, 3.0, 4.0, 5.0])); // [4.0, 2.0, 3.0, 5.0, 1.0]
// --- Distributions ---
let mut rng = Rng::from_string("demo-dist-additive");
println!("{}", Additive::new(0.0, 1.0).sample(&mut rng)); // 0.17410448679568188
let mut rng = Rng::from_string("demo-dist-multiplic");
println!("{}", Multiplic::new(0.0, 1.0).sample(&mut rng)); // 1.1273244602673853
let mut rng = Rng::from_string("demo-dist-exp");
println!("{}", Exp::new(1.0).sample(&mut rng)); // 0.6589065267276553
let mut rng = Rng::from_string("demo-dist-power");
println!("{}", Power::new(1.0, 2.0).sample(&mut rng)); // 1.023677535537084
let mut rng = Rng::from_string("demo-dist-uniform");
println!("{}", Uniform::new(0.0, 10.0).sample(&mut rng)); // 6.54043657816832
// --- Unit system ---
let ms = MeasurementUnit::new("ms", "Time", "ms", "Millisecond", 1_000_000);
let ns = MeasurementUnit::new("ns", "Time", "ns", "Nanosecond", 1);
let s = Sample::with_unit(vec![1.0, 2.0, 3.0], ms).unwrap();
let converted = s.convert_to(&ns).unwrap();
println!("Converted: {:?}", converted.values()); // [1000000.0, 2000000.0, 3000000.0]
let registry = UnitRegistry::standard();
let unit = registry.resolve("number").unwrap();
println!("Resolved: {}", unit.full_name()); // Number
}
```
--------------------------------
### Pragmastat Library Usage Demo
Source: https://pragmastat.dev/kt
Comprehensive examples covering one-sample and two-sample statistics, confirmatory comparisons, custom measurement units, randomization, and probability distributions.
```kotlin
package dev.pragmastat.demo
import dev.pragmastat.*
import dev.pragmastat.distributions.*
fun main() {
// --- One-Sample ---
val x = Sample.of((1..200).map { it.toDouble() })
println(center(x)) // 100.5
println(spread(x)) // 59.0
println(centerBounds(x, Probability(1e-3))) // Bounds(lower=86.0, upper=115.0, unit=...)
println(spreadBounds(x, Probability(1e-3), "demo")) // Bounds(lower=44.0, upper=87.0, unit=...)
// --- Two-Sample ---
val sx = Sample.of((1..200).map { it.toDouble() })
val sy = Sample.of((101..300).map { it.toDouble() })
println(shift(sx, sy)) // -100.0
println(shiftBounds(sx, sy, Probability(1e-3))) // Bounds(lower=-120.0, upper=-80.0, unit=...)
println(ratio(sx, sy)) // 0.5008354224706336
println(ratioBounds(sx, sy, Probability(1e-3))) // Bounds(lower=0.4066..., upper=0.5958..., unit=...)
println(disparity(sx, sy)) // -1.694915254237288
println(disparityBounds(sx, sy, Probability(1e-3), "demo")) // Bounds(lower=-3.1025..., upper=-0.8494..., unit=...)
// --- Confirmatory Comparison ---
println(compare1(sx, listOf(Threshold(Metric.Center, Measurement(50.0), Probability(1e-3))))[0].verdict.toId()) // greater
println(compare2(sx, sy, listOf(Threshold(Metric.Shift, Measurement(0.0), Probability(1e-3))))[0].verdict.toId()) // less
// --- Custom units ---
val ns = MeasurementUnit("ns", "Time", "ns", "Nanosecond", 1)
val us = MeasurementUnit("us", "Time", "us", "Microsecond", 1000)
val ms = MeasurementUnit("ms", "Time", "ms", "Millisecond", 1_000_000)
val registry = UnitRegistry.standard()
registry.register(ns)
registry.register(us)
registry.register(ms)
val timeSample = Sample.of(listOf(100.0, 200.0, 300.0, 400.0, 500.0), ns)
println(center(timeSample)) // 300 ns
println(center(timeSample.convertTo(us))) // 0.3 us
// --- Randomization ---
var rng = Rng("demo-uniform")
println(rng.uniformDouble()) // 0.2640554428629759
println(rng.uniformDouble()) // 0.9348534835582796
rng = Rng("demo-uniform-int")
println(rng.uniformInt(0, 100)) // 41
rng = Rng("demo-sample")
println(rng.sample(listOf(0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0), 3)) // [3.0, 8.0, 9.0]
rng = Rng("demo-resample")
println(rng.resample(listOf(1.0, 2.0, 3.0, 4.0, 5.0), 7)) // [3.0, 1.0, 3.0, 2.0, 4.0, 1.0, 2.0]
rng = Rng("demo-shuffle")
println(rng.shuffle(listOf(1.0, 2.0, 3.0, 4.0, 5.0))) // [4.0, 2.0, 3.0, 5.0, 1.0]
// --- Distributions ---
rng = Rng("demo-dist-additive")
println(Additive(0.0, 1.0).sample(rng)) // 0.17410448679568188
rng = Rng("demo-dist-multiplic")
println(Multiplic(0.0, 1.0).sample(rng)) // 1.1273244602673853
rng = Rng("demo-dist-exp")
println(Exp(1.0).sample(rng)) // 0.6589065267276553
rng = Rng("demo-dist-power")
println(Power(1.0, 2.0).sample(rng)) // 1.023677535537084
rng = Rng("demo-dist-uniform")
println(Uniform(0.0, 10.0).sample(rng)) // 6.54043657816832
}
```
--------------------------------
### Compare1 Usage Examples
Source: https://pragmastat.dev/compare1
Demonstrates comparing a sample against Center and Spread metrics with defined thresholds.
```text
Compare1([1..10], [(Center, 20, 1e-3)])
```
```text
Compare1([1..10], [(Spread, 0.1, 1e-3)])
```
--------------------------------
### Pragmastat Library Usage Demo
Source: https://pragmastat.dev/r
Comprehensive examples demonstrating one-sample and two-sample metrics, confirmatory comparisons, sample-based interfaces, randomization, and distribution sampling.
```R
library(pragmastat)
# --- One-Sample (legacy vector interface) ---
x <- 1:200
print(center(x)) # 100.5
bounds <- center_bounds(x, 1e-3)
print(paste("[", bounds$lower, ", ", bounds$upper, "]", sep = "")) # [86, 115]
print(spread(x)) # 59
bounds <- spread_bounds(x, 1e-3, seed = "demo")
print(paste("[", bounds$lower, ", ", bounds$upper, "]", sep = "")) # [44, 87]
# --- Two-Sample (legacy vector interface) ---
x <- 1:200
y <- 101:300
print(shift(x, y)) # -100
bounds <- shift_bounds(x, y, 1e-3)
print(paste("[", bounds$lower, ", ", bounds$upper, "]", sep = "")) # [-120, -80]
print(ratio(x, y)) # 0.500835
bounds <- ratio_bounds(x, y, 1e-3)
print(paste("[", bounds$lower, ", ", bounds$upper, "]", sep = "")) # [0.406666666666667, 0.595833333333333]
print(disparity(x, y)) # -1.694915
bounds <- disparity_bounds(x, y, 1e-3, seed = "demo")
print(paste("[", bounds$lower, ", ", bounds$upper, "]", sep = "")) # [-3.1025641025641, -0.849462365591398]
# --- Confirmatory Comparison ---
sx <- Sample$new(x)
t1 <- list(list(metric = METRIC_CENTER, value = Measurement$new(50), misrate = 1e-3))
print(compare1(sx, t1)[[1]]$verdict) # "greater"
sy <- Sample$new(y)
t2 <- list(list(metric = METRIC_SHIFT, value = Measurement$new(0), misrate = 1e-3))
print(compare2(sx, sy, t2)[[1]]$verdict) # "less"
# --- Sample-based interface ---
sx <- Sample$new(1:200)
m <- center(sx)
print(paste("center:", m$value, "unit:", m$unit$id))
b <- center_bounds(sx, 1e-3)
print(paste("center_bounds: [", b$lower, ", ", b$upper, "] unit:", b$unit$id, sep = ""))
sx <- Sample$new(1:200)
sy <- Sample$new(101:300)
m <- shift(sx, sy)
print(paste("shift:", m$value, "unit:", m$unit$id))
m <- ratio(sx, sy)
print(paste("ratio:", m$value, "unit:", m$unit$id))
# --- Randomization ---
r <- rng("demo-uniform")
print(r$uniform_float()) # 0.2640554
print(r$uniform_float()) # 0.9348535
r <- rng("demo-uniform-int")
print(r$uniform_int(0, 100)) # 41
r <- rng("demo-sample")
print(r$sample(0:9, 3)) # 3 8 9
r <- rng("demo-resample")
print(r$resample(c(1, 2, 3, 4, 5), 7)) # 3 1 3 2 4 1 2
r <- rng("demo-shuffle")
print(r$shuffle(c(1, 2, 3, 4, 5))) # 4 2 3 5 1
# --- Distributions ---
r <- rng("demo-dist-additive")
dist <- dist_additive(0, 1)
print(dist$sample(r)) # 0.1741045
r <- rng("demo-dist-multiplic")
dist <- dist_multiplic(0, 1)
print(dist$sample(r)) # 1.127324
r <- rng("demo-dist-exp")
dist <- dist_exp(1)
print(dist$sample(r)) # 0.6589065
r <- rng("demo-dist-power")
dist <- dist_power(1, 2)
print(dist$sample(r)) # 1.023678
r <- rng("demo-dist-uniform")
dist <- dist_uniform(0, 10)
print(dist$sample(r)) # 6.540437
```
--------------------------------
### Install Pragmastat via Build Systems
Source: https://pragmastat.dev/kt
Configuration snippets for adding Pragmastat as a dependency in Maven and Gradle projects.
```xml
dev.pragmastat
pragmastat
14.0.1
```
```groovy
implementation 'dev.pragmastat:pragmastat:14.0.1'
```
```kotlin
implementation("dev.pragmastat:pragmastat:14.0.1")
```
--------------------------------
### Shuffle Usage Examples
Source: https://pragmastat.dev/shuffle
Basic usage of the Shuffle method for generating a shuffled copy of an array.
```text
Rng("demo-shuffle").Shuffle([1, 2, 3, 4, 5])
```
```text
r.Shuffle(x)
```
--------------------------------
### Center Estimator Namespace Setup
Source: https://pragmastat.dev/center
Required imports and namespace declaration for the Pragmastat Center estimator implementation.
```csharp
using Pragmastat.Internal;
using Pragmastat.Randomization;
namespace Pragmastat.Algorithms;
```
--------------------------------
### Violation Schema Examples
Source: https://pragmastat.dev/assumptions
Standardized JSON format for reporting assumption violations.
```json
{
"id": "positivity",
"subject": "x"
}
```
```json
{
"id": "domain",
"subject": "misrate"
}
```
--------------------------------
### Reproducible Shuffle with Seed
Source: https://pragmastat.dev/shuffle
Example of passing a seeded generator to ensure reproducible results.
```text
Shuffle(data, Rng("experiment-1"))
```
--------------------------------
### Comparison Entry Points
Source: https://pragmastat.dev/compare1
Public methods for executing comparisons, enforcing metric compatibility constraints.
```csharp
public static IReadOnlyList Compare1(Sample x, IReadOnlyList thresholds, string? seed)
{
Assertion.NonWeighted("x", x);
Assertion.NotNullOrEmpty("thresholds", thresholds);
Assertion.ItemNotNull("thresholds", thresholds);
foreach (var threshold in thresholds)
{
if (threshold.Metric is Metric.Shift or Metric.Ratio or Metric.Disparity)
throw new ArgumentException(
$"Metric {threshold.Metric} is not supported by Compare1. Use Compare2 instead.",
nameof(thresholds));
}
foreach (var threshold in thresholds)
{
if (!threshold.Value.NominalValue.IsFinite())
throw new ArgumentOutOfRangeException(nameof(thresholds), "threshold.Value must be finite");
}
var normalizedValues = new Measurement[thresholds.Count];
for (int i = 0; i < thresholds.Count; i++)
{
var spec = GetSpec(Compare1Specs, thresholds[i].Metric);
normalizedValues[i] = spec.ValidateAndNormalize(thresholds[i], x, null);
}
return Execute(Compare1Specs, x, null, thresholds, normalizedValues, seed);
}
public static IReadOnlyList Compare2(
Sample x, Sample y, IReadOnlyList thresholds, string? seed)
{
Assertion.NonWeighted("x", x);
Assertion.NonWeighted("y", y);
Assertion.CompatibleUnits(x, y);
Assertion.NotNullOrEmpty("thresholds", thresholds);
Assertion.ItemNotNull("thresholds", thresholds);
foreach (var threshold in thresholds)
{
if (threshold.Metric is Metric.Center or Metric.Spread)
throw new ArgumentException(
$"Metric {threshold.Metric} is not supported by Compare2. Use Compare1 instead.",
nameof(thresholds));
}
```
--------------------------------
### Compare2 Algorithm Implementation
Source: https://pragmastat.dev/compare2
Core logic for validating inputs, normalizing metrics, and executing the comparison projection.
```csharp
public static IReadOnlyList Compare2(
Sample x, Sample y, IReadOnlyList thresholds, string? seed)
{
Assertion.NonWeighted("x", x);
Assertion.NonWeighted("y", y);
Assertion.CompatibleUnits(x, y);
Assertion.NotNullOrEmpty("thresholds", thresholds);
Assertion.ItemNotNull("thresholds", thresholds);
foreach (var threshold in thresholds)
{
if (threshold.Metric is Metric.Center or Metric.Spread)
throw new ArgumentException(
$"Metric {threshold.Metric} is not supported by Compare2. Use Compare1 instead.",
nameof(thresholds));
}
foreach (var threshold in thresholds)
{
if (!threshold.Value.NominalValue.IsFinite())
throw new ArgumentOutOfRangeException(nameof(thresholds), "threshold.Value must be finite");
}
var normalizedValues = new Measurement[thresholds.Count];
for (int i = 0; i < thresholds.Count; i++)
{
var spec = GetSpec(Compare2Specs, thresholds[i].Metric);
normalizedValues[i] = spec.ValidateAndNormalize(thresholds[i], x, y);
}
return Execute(Compare2Specs, x, y, thresholds, normalizedValues, seed);
}
private static MetricSpec GetSpec(MetricSpec[] specs, Metric metric)
{
foreach (var spec in specs)
if (spec.Metric == metric) return spec;
throw new ArgumentException($"No spec found for metric {metric}");
}
private static IReadOnlyList Execute(
MetricSpec[] canonicalSpecs,
Sample x,
Sample? y,
IReadOnlyList thresholds,
Measurement[] normalizedValues,
string? seed)
{
var results = new Projection[thresholds.Count];
var byMetric = thresholds
.Select((t, i) => (t, i, normalizedValues[i]))
.GroupBy(item => item.t.Metric)
.ToDictionary(g => g.Key, g => g.ToList());
foreach (var spec in canonicalSpecs)
{
if (!byMetric.TryGetValue(spec.Metric, out var entries)) continue;
var estimate = spec.Estimate(x, y);
foreach (var (threshold, inputIndex, normalizedValue) in entries)
{
var bounds = (seed != null && spec.SeededBounds != null)
? spec.SeededBounds(x, y, threshold.Misrate, seed)
: spec.Bounds(x, y, threshold.Misrate);
var verdict = ComputeVerdict(bounds, normalizedValue);
results[inputIndex] = new Projection(threshold, estimate, bounds, verdict);
}
}
return results;
}
private static ComparisonVerdict ComputeVerdict(Bounds bounds, Measurement normalizedThreshold)
{
double t = normalizedThreshold.NominalValue;
if (bounds.Lower > t) return ComparisonVerdict.Greater;
if (bounds.Upper < t) return ComparisonVerdict.Less;
return ComparisonVerdict.Inconclusive;
}
}
```
--------------------------------
### Input Preparation Helpers
Source: https://pragmastat.dev/spread
Utility methods for copying and validating input data, including an optional sorting step.
```csharp
private static double[] CopyAndSort(IReadOnlyList values)
{
var a = new double[values.Count];
for (int i = 0; i < a.Length; i++)
{
double v = values[i];
if (double.IsNaN(v)) throw new ArgumentException("NaN not allowed.", nameof(values));
a[i] = v;
}
Array.Sort(a);
return a;
}
private static double[] CopyTrusted(IReadOnlyList values)
{
// Trust caller that values are sorted; still copy to array for fast indexed access.
var a = new double[values.Count];
for (int i = 0; i < a.Length; i++)
{
double v = values[i];
if (double.IsNaN(v)) throw new ArgumentException("NaN not allowed.", nameof(values));
a[i] = v;
}
return a;
}
```
--------------------------------
### Sample Algorithm Implementation
Source: https://pragmastat.dev/sample
Pseudocode for the selection sampling algorithm that performs a single pass over the data.
```text
seen = 0, selected = 0
for each element x at position i:
if uniform() < (k - selected) / (n - seen):
output x
selected += 1
seen += 1
```
--------------------------------
### Implement Ratio Estimation in C#
Source: https://pragmastat.dev/ratio
Computes quantiles of pairwise ratios by delegating to the Shift algorithm in log-space. Requires input samples to be strictly positive.
```csharp
namespace Pragmastat.Algorithms;
using System;
using System.Collections.Generic;
using System.Linq;
using Pragmastat.Exceptions;
using Pragmastat.Internal;
///
/// Computes quantiles of pairwise ratios via log-transformation and ShiftImpl delegation.
/// Ratio(x, y) = exp(Shift(log(x), log(y)))
///
internal static class RatioImpl
{
///
/// Computes quantiles of all pairwise ratios { x_i / y_j }.
/// Time: O((m + n) * log(precision)) per quantile. Space: O(m + n).
///
///
/// Log-transformation preserves sort order for positive values.
///
/// First sample (must be strictly positive).
/// Second sample (must be strictly positive).
/// Probabilities in [0, 1].
/// If true, assumes x and y are already sorted in ascending order.
/// Quantile values for each probability in p.
public static double[] Estimate(IReadOnlyList x, IReadOnlyList y, double[] p, bool assumeSorted = false)
{
// Log-transform both samples (includes positivity check)
var logX = MathExtensions.Log(x, Subject.X);
var logY = MathExtensions.Log(y, Subject.Y);
// Delegate to ShiftImpl in log-space
var logResult = ShiftImpl.Estimate(logX, logY, p, assumeSorted);
// Exp-transform back to ratio-space
return logResult.Select(v => Math.Exp(v)).ToArray();
}
}
```
--------------------------------
### Compute Pairwise Quantiles and Bounds in C#
Source: https://pragmastat.dev/center-bounds
Provides methods to find the k-th smallest pairwise average and calculate lower and upper bounds for a sorted input list.
```csharp
using System.Diagnostics;
namespace Pragmastat.Algorithms;
///
/// Efficiently computes quantiles from all pairwise averages (x[i] + x[j]) / 2 for i ≤ j.
/// Uses binary search with counting function to avoid materializing all N(N+1)/2 pairs.
///
internal static class CenterQuantilesImpl
{
private static bool IsSorted(IReadOnlyList list)
{
for (int i = 1; i < list.Count; i++)
if (list[i] < list[i - 1])
return false;
return true;
}
///
/// Relative epsilon for floating-point comparisons in binary search convergence.
///
private const double RelativeEpsilon = 1e-14;
///
/// Compute specified quantile from pairwise averages.
///
/// Sorted input array.
/// 1-based rank of the desired quantile.
/// The k-th smallest pairwise average.
public static double Quantile(IReadOnlyList sorted, long k)
{
Debug.Assert(
IsSorted(sorted),
"CenterQuantilesImpl.Quantile: input must be sorted");
int n = sorted.Count;
if (n == 0)
throw new ArgumentException("Input cannot be empty", nameof(sorted));
long totalPairs = (long)n * (n + 1) / 2;
if (k < 1 || k > totalPairs)
throw new ArgumentOutOfRangeException(nameof(k), $"k must be in range [1, {totalPairs}]");
if (n == 1)
return sorted[0];
return FindExactQuantile(sorted, k);
}
///
/// Compute both lower and upper bounds from pairwise averages.
///
/// Sorted input array.
/// Rank of lower bound (1-based).
/// Rank of upper bound (1-based).
/// Lower and upper quantiles.
public static (double Lo, double Hi) Bounds(IReadOnlyList sorted, long marginLo, long marginHi)
{
Debug.Assert(
IsSorted(sorted),
"CenterQuantilesImpl.Bounds: input must be sorted");
int n = sorted.Count;
if (n == 0)
throw new ArgumentException("Input cannot be empty", nameof(sorted));
long totalPairs = (long)n * (n + 1) / 2;
marginLo = Max(1, Min(marginLo, totalPairs));
marginHi = Max(1, Min(marginHi, totalPairs));
double lo = FindExactQuantile(sorted, marginLo);
double hi = FindExactQuantile(sorted, marginHi);
return (Min(lo, hi), Max(lo, hi));
}
///
/// Count pairwise averages ≤ target value.
///
private static long CountPairsLessOrEqual(IReadOnlyList sorted, double target)
{
int n = sorted.Count;
long count = 0;
// j is not reset: as i increases, threshold decreases monotonically
int j = n - 1;
for (int i = 0; i < n; i++)
{
double threshold = 2 * target - sorted[i];
while (j >= 0 && sorted[j] > threshold)
j--;
if (j >= i)
count += j - i + 1;
}
return count;
}
///
/// Find exact k-th pairwise average using selection algorithm.
///
private static double FindExactQuantile(IReadOnlyList sorted, long k)
{
int n = sorted.Count;
long totalPairs = (long)n * (n + 1) / 2;
if (n == 1)
return sorted[0];
if (k == 1)
return sorted[0];
if (k == totalPairs)
return sorted[n - 1];
double lo = sorted[0];
double hi = sorted[n - 1];
const double eps = RelativeEpsilon;
var candidates = new List(n);
while (hi - lo > eps * Max(1.0, Max(Abs(lo), Abs(hi))))
{
double mid = 0.5 * lo + 0.5 * hi;
long countLessOrEqual = CountPairsLessOrEqual(sorted, mid);
if (countLessOrEqual >= k)
hi = mid;
else
lo = mid;
}
double target = 0.5 * lo + 0.5 * hi;
for (int i = 0; i < n; i++)
{
double threshold = 2 * target - sorted[i];
int left = i;
int right = n;
while (left < right)
{
int m = (left + right) / 2;
if (sorted[m] < threshold - eps)
left = m + 1;
else
right = m;
}
if (left < n && left >= i && Abs(sorted[left] - threshold) < eps * Max(1.0, Abs(threshold)))
candidates.Add(0.5 * sorted[i] + 0.5 * sorted[left]);
if (left > i)
{
double avgBefore = 0.5 * sorted[i] + 0.5 * sorted[left - 1];
if (avgBefore <= target + eps)
candidates.Add(avgBefore);
}
}
if (candidates.Count == 0)
return target;
candidates.Sort();
foreach (double candidate in candidates)
{
long countAtCandidate = CountPairsLessOrEqual(sorted, candidate);
if (countAtCandidate >= k)
return candidate;
}
return target;
}
}
```
--------------------------------
### Perform Statistical Analysis and Randomization
Source: https://pragmastat.dev/py
Demonstrates one-sample and two-sample metrics, confirmatory comparisons, random number generation, and sampling from various distributions.
```python
from pragmastat import (
Metric,
Rng,
Sample,
Threshold,
center,
center_bounds,
compare1,
compare2,
disparity,
disparity_bounds,
ratio,
ratio_bounds,
shift,
shift_bounds,
spread,
spread_bounds,
)
from pragmastat.distributions import Additive, Exp, Multiplic, Power, Uniform
def main():
# --- One-Sample ---
x = Sample(list(range(1, 201)))
result = center(x)
print(result.value) # 100.5
bounds = center_bounds(x, 1e-3)
print(f"Bounds(lower={bounds.lower}, upper={bounds.upper})") # Bounds(lower=86.0, upper=115.0)
print(spread(x).value) # 59.0
bounds = spread_bounds(x, 1e-3, seed="demo")
print(f"Bounds(lower={bounds.lower}, upper={bounds.upper})") # Bounds(lower=44.0, upper=87.0)
# --- Two-Sample ---
x = Sample(list(range(1, 201)))
y = Sample(list(range(101, 301)))
print(shift(x, y).value) # -100.0
bounds = shift_bounds(x, y, 1e-3)
print(f"Bounds(lower={bounds.lower}, upper={bounds.upper})") # Bounds(lower=-120.0, upper=-80.0)
print(ratio(x, y).value) # 0.5008354224706334
bounds = ratio_bounds(x, y, 1e-3)
print(
f"Bounds(lower={bounds.lower}, upper={bounds.upper})"
) # Bounds(lower=0.4066666666666668, upper=0.5958333333333332)
print(disparity(x, y).value) # -1.694915254237288
bounds = disparity_bounds(x, y, 1e-3, seed="demo")
print(
f"Bounds(lower={bounds.lower}, upper={bounds.upper})"
) # Bounds(lower=-3.1025641025641026, upper=-0.8494623655913979)
# --- Confirmatory Comparison ---
x = Sample(list(range(1, 201)))
projection = compare1(x, [Threshold(Metric.CENTER, 50.0, 1e-3)])[0]
print(projection.verdict.value) # greater
x = Sample(list(range(1, 201)))
y = Sample(list(range(101, 301)))
projection = compare2(x, y, [Threshold(Metric.SHIFT, 0.0, 1e-3)])[0]
print(projection.verdict.value) # less
# --- Randomization ---
rng = Rng("demo-uniform")
print(rng.uniform_float()) # 0.2640554428629759
print(rng.uniform_float()) # 0.9348534835582796
rng = Rng("demo-uniform-int")
print(rng.uniform_int(0, 100)) # 41
rng = Rng("demo-sample")
print(rng.sample([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], 3)) # [3, 8, 9]
rng = Rng("demo-resample")
print(rng.resample([1, 2, 3, 4, 5], 7)) # [3, 1, 3, 2, 4, 1, 2]
rng = Rng("demo-shuffle")
print(rng.shuffle([1, 2, 3, 4, 5])) # [4, 2, 3, 5, 1]
# --- Distributions ---
rng = Rng("demo-dist-additive")
print(Additive(0, 1).sample(rng)) # 0.17410448679568188
rng = Rng("demo-dist-multiplic")
print(Multiplic(0, 1).sample(rng)) # 1.1273244602673853
rng = Rng("demo-dist-exp")
print(Exp(1).sample(rng)) # 0.6589065267276553
rng = Rng("demo-dist-power")
print(Power(1, 2).sample(rng)) # 1.023677535537084
rng = Rng("demo-dist-uniform")
print(Uniform(0, 10).sample(rng)) # 6.54043657816832
if __name__ == "__main__":
main()
```