or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

array-operations.mdcombinatorics.mddata-manipulation.mddescriptive-statistics.mddistributions.mdindex.mdmachine-learning.mdmath-utilities.mdquantiles.mdregression.mdtesting.md

math-utilities.mddocs/

0

# Mathematical Utilities

1

2

Root finding, special functions, and numerical utilities for advanced mathematical operations.

3

4

## Core Imports

5

6

```typescript

7

import {

8

bisect,

9

factorial,

10

gamma,

11

gammaln,

12

sign,

13

numericSort,

14

quickselect,

15

epsilon,

16

combinations,

17

combinationsReplacement,

18

permutationsHeap,

19

equalIntervalBreaks

20

} from "simple-statistics";

21

```

22

23

## Root Finding

24

25

### bisect { .api }

26

27

```typescript { .api }

28

function bisect(

29

func: (x: any) => number,

30

start: number,

31

end: number,

32

maxIterations: number,

33

errorTolerance: number

34

): number;

35

```

36

37

Finds roots of a function using the bisection method - a robust numerical algorithm for finding where f(x) = 0.

38

39

**Parameters:**

40

- `func: (x: any) => number` - Function to find the root of

41

- `start: number` - Left boundary of search interval

42

- `end: number` - Right boundary of search interval

43

- `maxIterations: number` - Maximum number of iterations

44

- `errorTolerance: number` - Acceptable error tolerance

45

46

**Returns:** `number` - Root value where f(x) ≈ 0

47

48

**Requirements:** Function must be continuous and f(start) and f(end) must have opposite signs.

49

50

```typescript

51

import { bisect } from "simple-statistics";

52

53

// Find where x² - 4 = 0 (should be x = 2)

54

const quadratic = (x: number) => x * x - 4;

55

const root = bisect(quadratic, 0, 5, 100, 0.0001);

56

console.log(`Root of x² - 4 = 0: ${root}`); // ≈ 2.0000

57

58

// Find break-even point for business model

59

const profit = (price: number) => (price - 10) * (100 - price) - 200;

60

const breakEven = bisect(profit, 5, 50, 100, 0.01);

61

console.log(`Break-even price: $${breakEven.toFixed(2)}`);

62

```

63

64

## Special Functions

65

66

### factorial { .api }

67

68

```typescript { .api }

69

function factorial(n: number): number;

70

```

71

72

Calculates the factorial of a non-negative integer (n!).

73

74

**Parameters:**

75

- `n: number` - Non-negative integer

76

77

**Returns:** `number` - n! = n × (n-1) × ... × 2 × 1

78

79

```typescript

80

import { factorial } from "simple-statistics";

81

82

const fact5 = factorial(5); // 120

83

const fact0 = factorial(0); // 1 (by definition)

84

85

console.log(`5! = ${fact5}`);

86

87

// Combinatorics: number of ways to arrange 8 people

88

const arrangements = factorial(8); // 40,320

89

console.log(`Ways to arrange 8 people: ${arrangements.toLocaleString()}`);

90

```

91

92

### gamma { .api }

93

94

```typescript { .api }

95

function gamma(n: number): number;

96

```

97

98

Calculates the gamma function, which extends factorials to real numbers.

99

100

**Parameters:**

101

- `n: number` - Input value

102

103

**Returns:** `number` - Γ(n) value

104

105

**Properties:**

106

- Γ(n) = (n-1)! for positive integers

107

- Γ(1/2) = √π

108

- Γ(n+1) = n × Γ(n)

109

110

```typescript

111

import { gamma } from "simple-statistics";

112

113

const gamma4 = gamma(4); // 6 (same as 3!)

114

const gammaHalf = gamma(0.5); // √π ≈ 1.772

115

116

console.log(`Γ(4) = ${gamma4}`);

117

console.log(`Γ(0.5) = ${gammaHalf.toFixed(3)}`);

118

119

// Used in probability distributions

120

const betaFunction = (a: number, b: number) => (gamma(a) * gamma(b)) / gamma(a + b);

121

console.log(`Beta(2,3) = ${betaFunction(2, 3).toFixed(3)}`);

122

```

123

124

### gammaln { .api }

125

126

```typescript { .api }

127

function gammaln(n: number): number;

128

```

129

130

Calculates the natural logarithm of the gamma function. More numerically stable for large values.

131

132

**Parameters:**

133

- `n: number` - Input value

134

135

**Returns:** `number` - ln(Γ(n))

136

137

```typescript

138

import { gammaln } from "simple-statistics";

139

140

// For large values, use log form to avoid overflow

141

const largeGammaLn = gammaln(100); // ln(Γ(100))

142

console.log(`ln(Γ(100)) = ${largeGammaLn.toFixed(2)}`);

143

144

// Convert back if needed (for smaller results)

145

const largeGamma = Math.exp(largeGammaLn);

146

console.log(`Γ(100) ≈ ${largeGamma.toExponential(3)}`);

147

```

148

149

## Utility Functions

150

151

### sign { .api }

152

153

```typescript { .api }

154

function sign(x: number): number;

155

```

156

157

Returns the sign of a number.

158

159

**Parameters:**

160

- `x: number` - Input number

161

162

**Returns:** `number`

163

- 1 if x > 0

164

- -1 if x < 0

165

- 0 if x = 0

166

167

```typescript

168

import { sign } from "simple-statistics";

169

170

console.log(`sign(5) = ${sign(5)}`); // 1

171

console.log(`sign(-3) = ${sign(-3)}`); // -1

172

console.log(`sign(0) = ${sign(0)}`); // 0

173

174

// Direction of price movement

175

const priceChange = -2.5;

176

const direction = sign(priceChange) === 1 ? "up" : sign(priceChange) === -1 ? "down" : "flat";

177

console.log(`Price moved ${direction}`);

178

```

179

180

### numericSort { .api }

181

182

```typescript { .api }

183

function numericSort(array: number[]): number[];

184

```

185

186

Sorts an array of numbers in ascending order using proper numeric comparison.

187

188

**Parameters:**

189

- `array: number[]` - Array of numbers to sort

190

191

**Returns:** `number[]` - New sorted array (original array unchanged)

192

193

```typescript

194

import { numericSort } from "simple-statistics";

195

196

const unsorted = [10, 2, 30, 4, 5];

197

const sorted = numericSort(unsorted);

198

console.log(`Sorted: ${sorted}`); // [2, 4, 5, 10, 30]

199

200

// Proper numeric sorting vs. lexicographic

201

const badSort = [10, 2, 30, 4, 5].sort(); // ["10", "2", "30", "4", "5"] - wrong!

202

const goodSort = numericSort([10, 2, 30, 4, 5]); // [2, 4, 5, 10, 30] - correct!

203

```

204

205

### quickselect { .api }

206

207

```typescript { .api }

208

function quickselect<T>(array: T[], k: number, compare?: (a: T, b: T) => number): T;

209

```

210

211

Finds the k-th smallest element in an array using the quickselect algorithm (faster than full sorting).

212

213

**Parameters:**

214

- `array: T[]` - Array to search in

215

- `k: number` - Index of element to find (0-based)

216

- `compare?: (a: T, b: T) => number` - Optional comparison function

217

218

**Returns:** `T` - The k-th smallest element

219

220

```typescript

221

import { quickselect } from "simple-statistics";

222

223

const data = [7, 3, 1, 9, 2, 8, 5];

224

225

// Find median (middle element) without full sorting

226

const median = quickselect(data, Math.floor(data.length / 2));

227

console.log(`Median: ${median}`); // 5

228

229

// Find 3rd smallest element

230

const thirdSmallest = quickselect(data, 2); // 0-based index

231

console.log(`3rd smallest: ${thirdSmallest}`); // 3

232

233

// Custom comparison for objects

234

const people = [{age: 25}, {age: 30}, {age: 20}, {age: 35}];

235

const secondYoungest = quickselect(people, 1, (a, b) => a.age - b.age);

236

console.log(`Second youngest age: ${secondYoungest.age}`); // 25

237

```

238

239

### epsilon { .api }

240

241

```typescript { .api }

242

const epsilon: number;

243

```

244

245

Machine epsilon - the smallest representable positive number such that 1 + epsilon ≠ 1 in floating-point arithmetic.

246

247

```typescript

248

import { epsilon } from "simple-statistics";

249

250

console.log(`Machine epsilon: ${epsilon}`);

251

252

// Use for floating-point comparisons

253

function almostEqual(a: number, b: number): boolean {

254

return Math.abs(a - b) < epsilon * Math.max(Math.abs(a), Math.abs(b));

255

}

256

257

console.log(`0.1 + 0.2 === 0.3: ${0.1 + 0.2 === 0.3}`); // false

258

console.log(`0.1 + 0.2 ≈ 0.3: ${almostEqual(0.1 + 0.2, 0.3)}`); // true

259

```

260

261

## Combinatorics

262

263

### combinations { .api }

264

265

```typescript { .api }

266

function combinations<T>(array: T[], k: number): T[][];

267

```

268

269

Generates all possible combinations of k elements from an array.

270

271

**Parameters:**

272

- `array: T[]` - Source array

273

- `k: number` - Number of elements in each combination

274

275

**Returns:** `T[][]` - Array of all possible combinations

276

277

```typescript

278

import { combinations } from "simple-statistics";

279

280

const fruits = ['apple', 'banana', 'cherry', 'date'];

281

const pairs = combinations(fruits, 2);

282

283

console.log("All fruit pairs:");

284

pairs.forEach(pair => console.log(pair.join(' + ')));

285

// apple + banana, apple + cherry, apple + date, banana + cherry, etc.

286

287

// Team selection

288

const players = ['Alice', 'Bob', 'Charlie', 'David', 'Eve'];

289

const teams = combinations(players, 3);

290

console.log(`Possible 3-person teams: ${teams.length}`);

291

```

292

293

### combinationsReplacement { .api }

294

295

```typescript { .api }

296

function combinationsReplacement<T>(array: T[], k: number): T[][];

297

```

298

299

Generates combinations with replacement - elements can be repeated.

300

301

**Parameters:**

302

- `array: T[]` - Source array

303

- `k: number` - Number of elements in each combination

304

305

**Returns:** `T[][]` - Array of combinations with replacement

306

307

```typescript

308

import { combinationsReplacement } from "simple-statistics";

309

310

const dice = [1, 2, 3, 4, 5, 6];

311

const twoRolls = combinationsReplacement(dice, 2);

312

313

console.log("Possible dice combinations (with replacement):");

314

console.log(`Total combinations: ${twoRolls.length}`); // 21 combinations

315

```

316

317

### permutationsHeap { .api }

318

319

```typescript { .api }

320

function permutationsHeap<T>(array: T[]): T[][];

321

```

322

323

Generates all permutations of an array using Heap's algorithm.

324

325

**Parameters:**

326

- `array: T[]` - Source array

327

328

**Returns:** `T[][]` - Array of all permutations

329

330

```typescript

331

import { permutationsHeap } from "simple-statistics";

332

333

const letters = ['A', 'B', 'C'];

334

const perms = permutationsHeap(letters);

335

336

console.log("All permutations of ABC:");

337

perms.forEach(perm => console.log(perm.join('')));

338

// ABC, ACB, BAC, BCA, CAB, CBA

339

340

console.log(`Total permutations: ${perms.length}`); // 6 = 3!

341

```

342

343

## Data Binning

344

345

### equalIntervalBreaks { .api }

346

347

```typescript { .api }

348

function equalIntervalBreaks(values: number[], nClasses: number): number[];

349

```

350

351

Creates equal-width intervals for data binning and histogram creation.

352

353

**Parameters:**

354

- `values: number[]` - Data values

355

- `nClasses: number` - Number of intervals/classes

356

357

**Returns:** `number[]` - Array of break points defining intervals

358

359

```typescript

360

import { equalIntervalBreaks, min, max } from "simple-statistics";

361

362

// Age distribution binning

363

const ages = [22, 25, 28, 31, 35, 42, 48, 52, 58, 61, 67, 73];

364

const ageBreaks = equalIntervalBreaks(ages, 4);

365

366

console.log("Age group breaks:", ageBreaks);

367

// Example: [22, 34.75, 47.5, 60.25, 73]

368

369

// Create age groups

370

const ageGroups = [];

371

for (let i = 0; i < ageBreaks.length - 1; i++) {

372

const group = ages.filter(age => age >= ageBreaks[i] && age < ageBreaks[i + 1]);

373

ageGroups.push({

374

range: `${ageBreaks[i]}-${ageBreaks[i + 1]}`,

375

count: group.length,

376

ages: group

377

});

378

}

379

380

console.log("Age distribution:");

381

ageGroups.forEach(group => {

382

console.log(`${group.range}: ${group.count} people`);

383

});

384

```

385

386

## Usage Examples

387

388

### Numerical Analysis

389

390

```typescript

391

import { bisect, gamma, factorial } from "simple-statistics";

392

393

// Solve engineering problems numerically

394

class EngineeringCalculator {

395

// Find optimal pipe diameter for fluid flow

396

static findOptimalDiameter(flowRate: number, maxPressureDrop: number): number {

397

// Darcy-Weisbach equation simplified

398

const pressureDrop = (diameter: number) => {

399

const velocity = flowRate / (Math.PI * diameter * diameter / 4);

400

return 0.02 * (1 / diameter) * velocity * velocity * 1000 - maxPressureDrop;

401

};

402

403

return bisect(pressureDrop, 0.1, 2.0, 100, 0.001);

404

}

405

406

// Calculate reliability using gamma function

407

static weibullReliability(time: number, shape: number, scale: number): number {

408

return Math.exp(-Math.pow(time / scale, shape));

409

}

410

411

// Quality control calculations

412

static binomialCoefficient(n: number, k: number): number {

413

return factorial(n) / (factorial(k) * factorial(n - k));

414

}

415

}

416

417

// Usage examples

418

const optimalDiameter = EngineeringCalculator.findOptimalDiameter(0.5, 100);

419

console.log(`Optimal pipe diameter: ${optimalDiameter.toFixed(3)} m`);

420

421

const reliability = EngineeringCalculator.weibullReliability(1000, 2, 1500);

422

console.log(`Reliability after 1000 hours: ${(reliability * 100).toFixed(1)}%`);

423

```

424

425

### Combinatorial Optimization

426

427

```typescript

428

import { combinations, permutationsHeap, factorial } from "simple-statistics";

429

430

// Traveling salesman problem (small scale)

431

class TSPSolver {

432

private distances: number[][];

433

434

constructor(cities: string[], distanceMatrix: number[][]) {

435

this.distances = distanceMatrix;

436

}

437

438

// Brute force solution for small instances

439

solveExact(cities: string[]): { route: string[], distance: number } {

440

const routes = permutationsHeap(cities.slice(1)); // Fix first city

441

let bestRoute = cities;

442

let bestDistance = Infinity;

443

444

for (const route of routes) {

445

const fullRoute = [cities[0], ...route];

446

const distance = this.calculateRouteDistance(fullRoute);

447

448

if (distance < bestDistance) {

449

bestDistance = distance;

450

bestRoute = fullRoute;

451

}

452

}

453

454

return { route: bestRoute, distance: bestDistance };

455

}

456

457

private calculateRouteDistance(route: string[]): number {

458

let total = 0;

459

for (let i = 0; i < route.length - 1; i++) {

460

// Simplified - would need city name to index mapping

461

total += Math.random() * 100; // Placeholder

462

}

463

return total;

464

}

465

}

466

467

// Portfolio optimization - select best k stocks from n options

468

function selectOptimalPortfolio(stocks: any[], k: number): any[][] {

469

const portfolioCombinations = combinations(stocks, k);

470

471

// Evaluate each combination (simplified)

472

return portfolioCombinations.map(portfolio => ({

473

stocks: portfolio,

474

expectedReturn: portfolio.reduce((sum, stock) => sum + stock.expectedReturn, 0) / k,

475

risk: Math.sqrt(portfolio.reduce((sum, stock) => sum + stock.variance, 0) / k)

476

}));

477

}

478

```

479

480

### Scientific Computing

481

482

```typescript

483

import { gamma, gammaln, bisect } from "simple-statistics";

484

485

// Statistical distributions using special functions

486

class Distributions {

487

// Beta distribution probability density function

488

static betaPDF(x: number, alpha: number, beta: number): number {

489

if (x < 0 || x > 1) return 0;

490

491

const logBeta = gammaln(alpha) + gammaln(beta) - gammaln(alpha + beta);

492

return Math.exp((alpha - 1) * Math.log(x) + (beta - 1) * Math.log(1 - x) - logBeta);

493

}

494

495

// Find quantiles using bisection

496

static betaQuantile(p: number, alpha: number, beta: number): number {

497

const cdf = (x: number) => {

498

// Simplified incomplete beta function - would need proper implementation

499

return this.betaCDF(x, alpha, beta) - p;

500

};

501

502

return bisect(cdf, 0.001, 0.999, 100, 0.0001);

503

}

504

505

private static betaCDF(x: number, alpha: number, beta: number): number {

506

// Placeholder - would need proper incomplete beta implementation

507

return Math.pow(x, alpha) * Math.pow(1 - x, beta);

508

}

509

}

510

511

// Physics simulations

512

class PhysicsUtils {

513

// Stirling's approximation for large factorials

514

static stirlingApproximation(n: number): number {

515

return Math.sqrt(2 * Math.PI * n) * Math.pow(n / Math.E, n);

516

}

517

518

// Compare with actual gamma function

519

static compareStirling(n: number): void {

520

const actual = gamma(n + 1); // Γ(n+1) = n!

521

const approx = this.stirlingApproximation(n);

522

const error = Math.abs(actual - approx) / actual * 100;

523

524

console.log(`n=${n}: Actual=${actual.toExponential(3)}, Stirling=${approx.toExponential(3)}, Error=${error.toFixed(2)}%`);

525

}

526

}

527

528

// Test accuracy

529

[5, 10, 20, 50].forEach(n => PhysicsUtils.compareStirling(n));

530

```