Numbers

Matrices

Matrices as lists of rows: linear systems solved, inverses, determinants, products and transposes, and least-squares fits such as a trend line.

Version 1.0.0 · 6 functions · 1 crate

#maths#statistics#linear-algebra#forecasting

Functions

What use matrix.qwer gives a program, with the types Quillo sees. To take only some, or under other names: use matrix_solve, matrix_inverse from matrix (Quillo 0.6).

matrix_solve(a: list, b: list) → listor an error

The x with a · x = b: a a square matrix (a list of rows), b a list as long as a. An error when a is singular (no single answer).

matrix_inverse(a: list) → listor an error

The inverse of a square matrix, or an error when it has none.

matrix_determinant(a: list) → floator an error

The determinant of a square matrix (0 for a singular one).

matrix_multiply(a: list, b: list) → listor an error

The product a · b (as many columns in a as rows in b).

matrix_transpose(a: list) → listor an error

The matrix turned on its side: rows become columns.

matrix_least_squares(a: list, b: list) → listor an error

The x that makes a · x as close to b as can be (least squares), for more equations than unknowns: with rows [x, 1] it fits a line y = slope·x + intercept.

Get it

$ quillo install matrix               # matrix.qwer into this folder$ quillo install matrix --example     # and its example, matrix.qwe

Or with curl:

$ curl -O https://quillolang.org/plugins/files/matrix.qwer$ curl -O https://quillolang.org/plugins/files/matrix.qwe

Then, in your program, all of it or only what you call:

main.qwe
use matrix.qweruse matrix_solve, matrix_inverse from matrix      // Quillo 0.6: only these

It uses this crate, which cargo fetches the first time the plugin is built:

[dependencies]
nalgebra = { version = "0.33", default-features = false, features = ["std"] }

Example

matrix.qwe
// A bakery's numbers: what each loaf costs from three weeks of totals, the inverse of a transform,// and a trend line through monthly sales.////   quillo run matrix.qwe      then open http://localhost:8080/costsuse "matrix.qwer"// Three weeks of flour, butter and sugar used for bread, croissants and cakes (kg each),// and what they cost in total: the price of each ingredient per kg.route GET /costs {    let used = [[20, 2, 1], [10, 6, 3], [5, 3, 6]]    let paid = [41.5, 49.5, 36.0]    let p = matrix_solve(used, paid)?    { flour: p[0], butter: p[1], sugar: p[2] }}route GET /inverse = {    inverse: matrix_inverse([[4, 7], [2, 6]])?,    det: matrix_determinant([[4, 7], [2, 6]])?,    check: matrix_multiply([[4, 7], [2, 6]], matrix_inverse([[4, 7], [2, 6]])?)?,    singular: matrix_inverse([[1, 2], [2, 4]]).error,}route GET /trend {    let sales = [120, 135, 149, 160, 178, 190]    let fit = matrix_least_squares(range(len(sales)) | map((m) => [float(m), 1.0]), sales)?    { per_month: round(fit[0], 2), start: round(fit[1], 2), month_7: round(fit[0] * 6 + fit[1], 1) }}
$ quillo run matrix.qwe$ curl 'localhost:8080/costs'$ curl 'localhost:8080/inverse'$ curl 'localhost:8080/trend'

Source

matrix.qwer
//! Matrices as lists of rows: linear systems solved, inverses, determinants, products and transposes, and least-squares fits (a trend line through points). For pricing models, physics, statistics and graphics.//! version: 1.0.0//!//! [dependencies]//! nalgebra = { version = "0.33", default-features = false, features = ["std"] }use nalgebra::{DMatrix, DVector};const MAX: usize = 500;fn mat(rows: &[Vec<f64>], what: &str) -> Result<DMatrix<f64>, String> {    let n = rows.len();    let m = rows.first().map(Vec::len).unwrap_or(0);    if n == 0 || m == 0 {        return Err(format!("{} is empty", what));    }    if n > MAX || m > MAX {        return Err(format!("{} is at most {} by {}", what, MAX, MAX));    }    if let Some(i) = rows.iter().position(|r| r.len() != m) {        return Err(format!("row {} of {} has {} numbers, not {}", i, what, rows[i].len(), m));    }    if rows.iter().flatten().any(|x| !x.is_finite()) {        return Err(format!("{} holds a number that is not finite", what));    }    Ok(DMatrix::from_fn(n, m, |i, j| rows[i][j]))}/// Rounds away float dust: 1e-12 becomes 0, 2.0000000000004 becomes 2.fn clean(x: f64) -> f64 {    let y = (x * 1e10).round() / 1e10;    if y == 0.0 { 0.0 } else { y }}fn rows(m: &DMatrix<f64>) -> Vec<Vec<f64>> {    (0..m.nrows()).map(|i| (0..m.ncols()).map(|j| clean(m[(i, j)])).collect()).collect()}/// The `x` with `a · x = b`: `a` a square matrix (a list of rows), `b` a list as long as `a`. An error when `a` is singular (no single answer).pub fn matrix_solve(a: Vec<Vec<f64>>, b: Vec<f64>) -> Result<Vec<f64>, String> {    let a = mat(&a, "a")?;    if a.nrows() != a.ncols() {        return Err("a must be square: use matrix_least_squares for more equations than unknowns".into());    }    if b.len() != a.nrows() {        return Err(format!("b has {} numbers; a has {} rows", b.len(), a.nrows()));    }    let x = a.lu().solve(&DVector::from_vec(b)).ok_or("a is singular: the equations have no single solution")?;    Ok(x.iter().map(|v| clean(*v)).collect())}/// The inverse of a square matrix, or an error when it has none.pub fn matrix_inverse(a: Vec<Vec<f64>>) -> Result<Vec<Vec<f64>>, String> {    let a = mat(&a, "a")?;    if a.nrows() != a.ncols() {        return Err("only a square matrix has an inverse".into());    }    Ok(rows(&a.try_inverse().ok_or("the matrix is singular: it has no inverse")?))}/// The determinant of a square matrix (0 for a singular one).pub fn matrix_determinant(a: Vec<Vec<f64>>) -> Result<f64, String> {    let a = mat(&a, "a")?;    if a.nrows() != a.ncols() {        return Err("only a square matrix has a determinant".into());    }    Ok(clean(a.determinant()))}/// The product `a · b` (as many columns in `a` as rows in `b`).pub fn matrix_multiply(a: Vec<Vec<f64>>, b: Vec<Vec<f64>>) -> Result<Vec<Vec<f64>>, String> {    let (a, b) = (mat(&a, "a")?, mat(&b, "b")?);    if a.ncols() != b.nrows() {        return Err(format!("a has {} columns but b has {} rows", a.ncols(), b.nrows()));    }    Ok(rows(&(a * b)))}/// The matrix turned on its side: rows become columns.pub fn matrix_transpose(a: Vec<Vec<f64>>) -> Result<Vec<Vec<f64>>, String> {    Ok(rows(&mat(&a, "a")?.transpose()))}/// The `x` that makes `a · x` as close to `b` as can be (least squares), for more equations than unknowns: with rows `[x, 1]` it fits a line `y = slope·x + intercept`.pub fn matrix_least_squares(a: Vec<Vec<f64>>, b: Vec<f64>) -> Result<Vec<f64>, String> {    let a = mat(&a, "a")?;    if b.len() != a.nrows() {        return Err(format!("b has {} numbers; a has {} rows", b.len(), a.nrows()));    }    let x = a.svd(true, true).solve(&DVector::from_vec(b), 1e-12)?;    Ok(x.iter().map(|v| clean(*v)).collect())}
Clustering clustering.qwer · 1.0.0Data put into groups: k-means with k chosen by the elbow and silhouette, DBSCAN for groups of any shape and their outliers (in metres for latitude and longitude), and hierarchical clustering, on rows of numbers or maps.statisticsanalyticssegmentsgeomaths7 views · 7 downloadsForecasting forecast.qwer · 1.0.0Forecasts from a series of numbers: moving averages, exponential smoothing, Holt's trend and Holt-Winters seasons with their weights fitted, the best model chosen on held-out data, prediction intervals, and accuracy measures.forecastingstatisticsanalyticsplanning8 views · 9 downloadsRandom distributions random_dist.qwer · 1.0.0Seeded samples from normal, log-normal, Poisson, exponential and binomial distributions, with a summary, for simulations and test data.simulationstatisticstestingforecasting7 views · 9 downloadsStatistical tests statistics.qwer · 1.0.0Statistical tests and regression beyond Quillo's stats: t-tests (one-sample, paired, Welch), ANOVA, chi-square tests, Mann-Whitney U, correlation with its p-value, confidence intervals, and multiple linear regression with standard errors and p-values.statisticsmathsanalyticsexperiments7 views · 7 downloadsAnomaly detection anomalies.qwer · 1.0.0Outliers and odd moments found in numbers: z-scores, the robust MAD score, IQR fences and Grubbs' test; and in series over time, spikes against a rolling window or the same hour of past days, EWMA control limits and level shifts by CUSUM.statisticsmonitoringalertsanalytics8 views · 8 downloadsBig numbers bignum.qwer · 1.0.0Integers and fractions of any size, exact: factorials, powers, gcd, modular powers, and fractions such as 1/3 + 1/6 = 1/2 with no rounding.mathsmoneyexactfractions8 views · 7 downloads
Thread
78Useful? Like it, or add to its thread below.

Thread 0 posts

On Matrices: questions, tips, corrections, and code that uses it.

No posts yet. The first one opens the thread.