{"id":13731553,"url":"https://github.com/sgorsten/linalg","last_synced_at":"2026-01-18T15:06:21.877Z","repository":{"id":39003109,"uuid":"52693693","full_name":"sgorsten/linalg","owner":"sgorsten","description":"linalg.h is a single header, public domain, short vector math library for C++","archived":false,"fork":false,"pushed_at":"2023-07-02T21:41:57.000Z","size":496,"stargazers_count":901,"open_issues_count":6,"forks_count":68,"subscribers_count":29,"default_branch":"main","last_synced_at":"2025-05-08T04:37:11.340Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"unlicense","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/sgorsten.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null}},"created_at":"2016-02-27T23:18:22.000Z","updated_at":"2025-05-07T10:44:47.000Z","dependencies_parsed_at":"2022-07-09T18:30:16.580Z","dependency_job_id":"b1e214ea-e2ca-4052-8e3d-6a4558037d1b","html_url":"https://github.com/sgorsten/linalg","commit_stats":null,"previous_names":[],"tags_count":3,"template":false,"template_full_name":null,"purl":"pkg:github/sgorsten/linalg","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sgorsten%2Flinalg","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sgorsten%2Flinalg/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sgorsten%2Flinalg/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sgorsten%2Flinalg/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/sgorsten","download_url":"https://codeload.github.com/sgorsten/linalg/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sgorsten%2Flinalg/sbom","scorecard":{"id":814473,"data":{"date":"2025-08-11","repo":{"name":"github.com/sgorsten/linalg","commit":"4460f1f5b85ccc81ffcf49aa450d454db58ca90e"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":3,"checks":[{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Dangerous-Workflow","score":-1,"reason":"no workflows found","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Code-Review","score":0,"reason":"Found 2/28 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Token-Permissions","score":-1,"reason":"No tokens found","details":null,"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Pinned-Dependencies","score":-1,"reason":"no dependencies found","details":null,"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: UNLICENSE:0","Info: FSF or OSI recognized license: The Unlicense: UNLICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'main'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 4 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}}]},"last_synced_at":"2025-08-23T13:54:59.322Z","repository_id":39003109,"created_at":"2025-08-23T13:54:59.328Z","updated_at":"2025-08-23T13:54:59.328Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28538933,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-18T14:59:57.589Z","status":"ssl_error","status_checked_at":"2026-01-18T14:59:46.540Z","response_time":98,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-08-03T02:01:32.686Z","updated_at":"2026-01-18T15:06:21.838Z","avatar_url":"https://github.com/sgorsten.png","language":"C++","readme":"# linalg.h\n\n[![Release is 2.2](https://img.shields.io/badge/version-2.2-blue.svg)](http://raw.githubusercontent.com/sgorsten/linalg/v3/linalg.h)\n[![License is Unlicense](http://img.shields.io/badge/license-Unlicense-blue.svg?style=flat)](http://unlicense.org/)\n[![Travis CI build status](http://travis-ci.org/sgorsten/linalg.svg)](https://travis-ci.org/sgorsten/linalg)\n[![Appveyor build status](http://ci.appveyor.com/api/projects/status/l4bfv5omodkajuc9?svg=true)](https://ci.appveyor.com/project/sgorsten/linalg)\n\n[`linalg.h`](/linalg.h) is a [single header](http://github.com/nothings/stb/blob/master/docs/other_libs.md), [public domain](http://unlicense.org/), [short vector math](http://www.reedbeta.com/blog/on-vector-math-libraries/) library for [C++](http://en.cppreference.com/w/). It is inspired by the syntax of popular shading and compute languages and is intended to serve as a lightweight alternative to projects such as [GLM](http://glm.g-truc.net/0.9.7/), [Boost.QVM](https://www.boost.org/doc/libs/1_66_0/libs/qvm/doc/index.html) or [Eigen](http://eigen.tuxfamily.org/) in domains such as computer graphics, computational geometry, and physical simulation. It allows you to easily write programs like the following:\n\n```cpp\n#include \u003clinalg.h\u003e\nusing namespace linalg::aliases;\n\n// Compute the coefficients of the equation of a plane containing points a, b, and c\nfloat4 compute_plane(float3 a, float3 b, float3 c)\n{\n    float3 n = cross(b-a, c-a);\n    return {n, -dot(n,a)};\n}\n```\n\n`linalg.h` aims to be:\n\n* **Lightweight**: The library is defined in a single header file which is less than a thousand lines of code.\n* **Dependency free**: There are no dependencies beyond a compliant C++11 compiler and a small subset of the standard library.\n* **Standards compliant**: Almost all operations are free of undefined behavior and can be evaluated in a `constexpr` context.\n* **Generic**: All types and operations are parameterized over scalar type, and can be mixed within expressions. Type promotion rules roughly match the C standard.\n* **Consistent**: Named functions and overloaded operators perform the same conceptual operation on all data types for which they are supported.\n* **Complete**: There are very few restrictions on which operations may be applied to which data types.\n* **Easy to integrate**: The library defines no symbols in the public namespace, and provides a mechanism for defining implicit conversions to external or user-provided data types.\n\nThe documentation for `v2.2` is still in progress.\n\n* [Data structures](#data-structures)\n  * [Vectors](#vectors)\n  * [Matrices](#matrices)\n* [Function listing](#function-listing)\n  * [Vector algebra](#vector-algebra)\n  * [Quaternion algebra](#quaternion-algebra)  \n  * [Matrix algebra](#matrix-algebra)\n  * [Component-wise operations](#component-wise-operations)\n  * [Reductions](#reductions)\n* [Optional features](#optional-features)\n  * [Type aliases](#type-aliases)\n  * [`ostream` overloads](#ostream-overloads)\n  * [User-defined conversions](#user-defined-conversions)\n* [Higher order functions](#higher-order-functions)\n* [Changes from v2.1](#changes-from-v21)\n\n## Data structures\n\n#### Vectors\n\n`linalg::vec\u003cT,M\u003e` defines a fixed-length vector containing exactly `M` elements of type `T`. Convenience aliases such as `float3`, `float4`, or `int2` are provided in the [`linalg::aliases` namespace](#type-aliases). This data structure can be used to store a wide variety of types of data, including geometric vectors, points, homogeneous coordinates, plane equations, colors, texture coordinates, or any other situation where you need to manipulate a small sequence of numbers. As such, `vec\u003cT,M\u003e` is supported by a set of [algebraic](#vector-algebra) and [component-wise](#component-wise-operations) functions, as well as a set of standard [reductions](#reductions).\n\n`vec\u003cT,M\u003e`:\n* is [`DefaultConstructible`](https://en.cppreference.com/w/cpp/named_req/DefaultConstructible):\n  ```cpp\n  float3 v; // v contains 0,0,0\n  ```\n* is constructible from `M` elements of type `T`:\n  ```cpp\n  float3 v {1,2,3}; // v contains 1,2,3\n  ```\n* is [`CopyConstructible`](https://en.cppreference.com/w/cpp/named_req/CopyConstructible) and [`CopyAssignable`](https://en.cppreference.com/w/cpp/named_req/CopyAssignable): \n  ```cpp\n  float3 v {1,2,3}; // v contains 1,2,3\n  float3 u {v};     // u contains 1,2,3\n  float3 w;         // w contains 0,0,0 \n  w = u;            // w contains 1,2,3\n  ```\n* is [`EqualityComparable`](https://en.cppreference.com/w/cpp/named_req/EqualityComparable) and [`LessThanComparable`](https://en.cppreference.com/w/cpp/named_req/LessThanComparable):\n  ```cpp\n  if(v == y) cout \u003c\u003c \"v and u contain equal elements in the same positions\" \u003c\u003c endl;\n  if(v \u003c u) cout \u003c\u003c \"v precedes u lexicographically\" \u003c\u003c endl;\n  ```  \n* is **explicitly** constructible from a single element of type `T`:\n  ```cpp\n  float3 v = float3{4}; // v contains 4,4,4\n  ```\n* is **explicitly** constructible from a `vec\u003cU,M\u003e` of some other type `U`:\n  ```cpp\n  float3 v {1.1f,2.3f,3.5f}; // v contains 1.1,2.3,3.5\n  int3 u = int3{v};          // u contains 1,2,3\n  ```\n* has fields `x,y,z,w`:\n  ```cpp\n  float y = point.y;    // y contains second element of point\n  pixel.w = 0.5;        // fourth element of pixel set to 0.5\n  float s = tc.x;       // s contains first element of tc\n  ```\n* supports indexing: \n  ```cpp\n  float x = v[0]; // x contains first element of v\n  v[2] = 5;       // third element of v set to 5\n  ```\n* supports unary operators `+`, `-`, `!` and `~` in component-wise fashion: \n  ```cpp\n  auto v = -float{2,3}; // v is float2{-2,-3}\n  ```\n* supports binary operators `+`, `-`, `*`, `/`, `%`, `|`, `\u0026`, `^`, `\u003c\u003c` and `\u003e\u003e` in component-wise fashion: \n  ```cpp\n  auto v = float2{1,1} + float2{2,3}; // v is float2{3,4}\n  ```\n* supports binary operators with a scalar on the left or the right:\n  ```cpp\n  auto v = 2 * float3{1,2,3}; // v is float3{2,4,6}\n  auto u = float3{1,2,3} + 1; // u is float3{2,3,4}\n  ```\n* supports operators `+=`, `-=`, `*=`, `/=`, `%=`, `|=`, `\u0026=`, `^=`, `\u003c\u003c=` and `\u003e\u003e=` with vectors or scalars on the right:\n  ```cpp\n  float2 v {1,2}; v *= 3; // v is float2{3,6}\n  ```\n* supports operations on mixed element types: \n  ```cpp\n  auto v = float3{1,2,3} + int3{4,5,6}; // v is float3{5,7,9}\n  ```\n* supports [range-based for](https://en.cppreference.com/w/cpp/language/range-for):\n  ```cpp\n  for(auto elem : float3{1,2,3}) cout \u003c\u003c elem \u003c\u003c ' '; // prints \"1 2 3 \"\n  ```\n* has a flat memory layout: \n  ```cpp\n  float3 v {1,2,3}; \n  float * p = v.data(); // \u0026v[i] == p+i\n  p[1] = 4; // v contains 1,4,3\n  ```\n\n#### Matrices\n\n`linalg::mat\u003cT,M,N\u003e` defines a fixed-size matrix containing exactly `M` rows and `N` columns of type `T`, in column-major order. Convenience aliases such as `float4x4` or `double3x3` are provided in the [`linalg::aliases` namespace](#type-aliases). This data structure is supported by a set of [algebraic](#matrix-algebra) functions and [component-wise](#component-wise-operations) functions, as well as a set of standard [reductions](#reductions).\n\n`mat\u003cT,M,N\u003e`:\n* is [`DefaultConstructible`](https://en.cppreference.com/w/cpp/named_req/DefaultConstructible):\n  ```cpp\n  float2x2 m; // m contains columns 0,0; 0,0\n  ```\n* is constructible from `N` columns of type `vec\u003cT,M\u003e`: \n  ```cpp\n  float2x2 m {{1,2},{3,4}}; // m contains columns 1,2; 3,4\n  ```\n* is constructible from `linalg::identity`:\n  ```cpp\n  float3x3 m = linalg::identity; // m contains columns 1,0,0; 0,1,0; 0,0,1\n  ```\n* is [`CopyConstructible`](https://en.cppreference.com/w/cpp/named_req/CopyConstructible) and [`CopyAssignable`](https://en.cppreference.com/w/cpp/named_req/CopyAssignable): \n  ```cpp\n  float2x2 m {{1,2},{3,4}}; // m contains columns 1,2; 3,4\n  float2x2 n {m};           // n contains columns 1,2; 3,4\n  float2x2 p;               // p contains columns 0,0; 0,0\n  p = n;                    // p contains columns 1,2; 3,4\n  ```\n* is [`EqualityComparable`](https://en.cppreference.com/w/cpp/named_req/EqualityComparable) and [`LessThanComparable`](https://en.cppreference.com/w/cpp/named_req/LessThanComparable):\n  ```cpp\n  if(m == n) cout \u003c\u003c \"m and n contain equal elements in the same positions\" \u003c\u003c endl;\n  if(m \u003c n) cout \u003c\u003c \"m precedes n lexicographically when compared in column-major order\" \u003c\u003c endl;\n  ```  \n* is **explicitly** constructible from a single element of type `T`: \n  ```cpp\n  float2x2 m {5}; // m contains columns 5,5; 5,5\n  ```\n* is **explicitly** constructible from a `mat\u003cU,M,N\u003e` of some other type `U`: \n  ```cpp\n  float2x2 m {int2x2{{5,6},{7,8}}}; // m contains columns 5,6; 7,8\n  ```\n* supports indexing into *columns*: \n  ```cpp\n  float2x3 m {{1,2},{3,4},{5,6}}; // m contains columns 1,2; 3,4; 5,6\n  float2 c = m[0];                // c contains 1,2\n  m[1]     = {7,8};               // m contains columns 1,2; 7,8; 5,6\n  ```\n* supports retrieval (but not assignment) of rows:\n  ```cpp\n  float2x3 m {{1,2},{3,4},{5,6}}; // m contains columns 1,2; 3,4; 5,6\n  float3 r = m.row(1);            // r contains 2,4,6\n  ```\n  \n  \n  \n* supports unary operators `+`, `-`, `!` and `~` in component-wise fashion:\n  ```cpp\n  float2x2 m {{1,2},{3,4}}; // m contains columns 1,2; 3,4\n  float2x2 n = -m;          // n contains columns -1,-2; -3,-4\n  ```\n* supports binary operators `+`, `-`, `*`, `/`, `%`, `|`, `\u0026`, `^`, `\u003c\u003c` and `\u003e\u003e` in component-wise fashion:\n  ```cpp\n  float2x2 a {{0,0},{2,2}}; // a contains columns 0,0; 2,2\n  float2x2 b {{1,2},{1,2}}; // b contains columns 1,2; 1,2\n  float2x2 c = a + b;       // c contains columns 1,2; 3,4\n  ```\n  \n* supports binary operators with a scalar on the left or the right:\n  ```cpp\n  auto m = 2 * float2x2{{1,2},{3,4}}; // m is float2x2{{2,4},{6,8}}\n  ```  \n  \n* supports operators `+=`, `-=`, `*=`, `/=`, `%=`, `|=`, `\u0026=`, `^=`, `\u003c\u003c=` and `\u003e\u003e=` with matrices or scalars on the right:\n  ```cpp\n  float2x2 v {{5,4},{3,2}}; \n  v *= 3; // v is float2x2{{15,12},{9,6}}\n  ```  \n  \n* supports operations on mixed element types: \n  \n* supports [range-based for](https://en.cppreference.com/w/cpp/language/range-for) over columns\n\n* has a flat memory layout\n\n## Function listing\n\n#### Vector algebra\n\n* `cross(vec\u003cT,3\u003e a, vec\u003cT,3\u003e b) -\u003e vec\u003cT,3\u003e` is the [cross or vector product](https://en.wikipedia.org/wiki/Cross_product) of vectors `a` and `b`\n  * `cross(vec\u003cT,2\u003e a, vec\u003cT,2\u003e b) -\u003e T` is shorthand for `cross({a.x,a.y,0}, {b.x,b.y,0}).z`\n  * `cross(T a, vec\u003cT,2\u003e b) -\u003e vec\u003cT,2\u003e` is shorthand for `cross({0,0,a.z}, {b.x,b.y,0}).xy()`\n  * `cross(vec\u003cT,2\u003e a, T b) -\u003e vec\u003cT,2\u003e` is shorthand for `cross({a.x,a.y,0}, {0,0,b.z}).xy()`\n\n* `dot(vec\u003cT,M\u003e a, vec\u003cT,M\u003e b) -\u003e T` is the [dot or inner product](https://en.wikipedia.org/wiki/Dot_product) of vectors `a` and `b`\n\n* `length(vec\u003cT,M\u003e a) -\u003e T` is the length or magnitude of a vector `a`\n* `length2(vec\u003cT,M\u003e a) -\u003e T` is the *square* of the length or magnitude of vector `a`\n* `normalize(vec\u003cT,M\u003e a) -\u003e vec\u003cT,M\u003e` is a unit length vector in the same direction as `a` (undefined for zero-length vectors)\n\n* `distance(vec\u003cT,M\u003e a, vec\u003cT,M\u003e b) -\u003e T` is the [Euclidean distance](https://en.wikipedia.org/wiki/Euclidean_distance) between points `a` and `b`\n* `distance2(vec\u003cT,M\u003e a, vec\u003cT,M\u003e b) -\u003e T` is the *square* of the [Euclidean distance](https://en.wikipedia.org/wiki/Euclidean_distance) between points `a` and `b`\n\n* `angle(vec\u003cT,M\u003e a, vec\u003cT,M\u003e b) -\u003e T` is the angle in [radians](https://en.wikipedia.org/wiki/Radian) between vectors `a` and `b`\n* `uangle(vec\u003cT,M\u003e a, vec\u003cT,M\u003e b) -\u003e T` is the angle in [radians](https://en.wikipedia.org/wiki/Radian) between unit vectors `a` and `b` (undefined for non-unit vectors)\n* `rot(T a, vec\u003cT,2\u003e v) -\u003e vec\u003cT,2\u003e` is the vector `v` rotated counter-clockwise by the angle `a` in [radians](https://en.wikipedia.org/wiki/Radian)\n\n* `nlerp(vec\u003cT,M\u003e a, vec\u003cT,M\u003e b, T t) -\u003e vec\u003cT,M\u003e` is shorthand for `normalize(lerp(a,b,t))`\n* `slerp(vec\u003cT,M\u003e a, vec\u003cT,M\u003e b, T t) -\u003e vec\u003cT,M\u003e` is the [spherical linear interpolation](https://en.wikipedia.org/wiki/Slerp) between unit vectors `a` and `b` (undefined for non-unit vectors) by parameter `t`\n\n#### Quaternion algebra\n\nA small set of functions provides support for quaternion math, using `vec\u003cT,4\u003e` values to represent quaternions of the form `xi + yj + zk + w`.\n\n* `qmul(vec\u003cT,4\u003e a, vec\u003cT,4\u003e b) -\u003e vec\u003cT,4\u003e` is the [Hamilton product](https://en.wikipedia.org/wiki/Quaternion#Hamilton_product) of quaternions `a` and `b`\n* `qconj(vec\u003cT,4\u003e q) -\u003e vec\u003cT,4\u003e` is the [conjugate](https://en.wikipedia.org/wiki/Quaternion#Conjugation,_the_norm,_and_reciprocal) of quaternion `q`\n* `qinv(vec\u003cT,4\u003e q) -\u003e vec\u003cT,4\u003e` is the [inverse or reciprocal](https://en.wikipedia.org/wiki/Quaternion#Conjugation,_the_norm,_and_reciprocal) of quaternion `q` (undefined for zero-length quaternions)\n\n* `qexp(vec\u003cT,4\u003e q) -\u003e vec\u003cT,4\u003e` is the [exponential](https://en.wikipedia.org/wiki/Quaternion#Exponential,_logarithm,_and_power_functions) of quaternion `q`\n* `qlog(vec\u003cT,4\u003e q) -\u003e vec\u003cT,4\u003e` is the [logarithm](https://en.wikipedia.org/wiki/Quaternion#Exponential,_logarithm,_and_power_functions) of quaternion `q`\n* `qpow(vec\u003cT,4\u003e q T p) -\u003e vec\u003cT,4\u003e` is the quaternion `q` raised to the exponent `p`\n\nA second set of functions provides support for using unit-length quaternions to represent 3D spatial rotations. Their results are undefined for quaternions which are not of unit-length.\n\n* `qangle(vec\u003cT,4\u003e q)` is the angle in radians of the rotation expressed by quaternion `q`\n* `qaxis(vec\u003cT,4\u003e q)` is the axis of rotation expression by quaternion `q` (undefined for zero-angle quaternions)\n* `qrot(vec\u003cT,4\u003e q, vec\u003cT,3\u003e v) -\u003e vec\u003cT,3\u003e` is vector `v` rotated via rotation quaternion `q`\n\n* `qmat(vec\u003cT,4\u003e q)` is a 3x3 rotation matrix which performs the same operation as rotation quaternion `q`\n* `qxdir(vec\u003cT,4\u003e q)` is (efficient) shorthand for `qrot(q, {1,0,0})`\n* `qydir(vec\u003cT,4\u003e q)` is (efficient) shorthand for `qrot(q, {0,1,0})`\n* `qzdir(vec\u003cT,4\u003e q)` is (efficient) shorthand for `qrot(q, {0,0,1})`  \n\nIt is possible to use the `nlerp` and `slerp` functions to interpolate rotation quaternions as though they were simply four-dimensional vectors. However, the rotation quaternions form a [double cover](https://en.wikipedia.org/wiki/Covering_group) over spatial rotations in three dimensions. This means that there are **two** distinct rotation quaternions representing each spatial rotation. Naively interpolating between two spatial rotations using quaternions could follow the \"short path\" or the \"long path\" between these rotations, depending on which specific quaternions are being interpolated. \n\n* `qnlerp(vec\u003cT,4\u003e a, vec\u003cT,4\u003e b, T t)` is similar to `nlerp(a,b,t)`, but always chooses the \"short path\" between the rotations represented by `a` and `b`.\n* `qslerp(vec\u003cT,4\u003e a, vec\u003cT,4\u003e b, T t)` is similar to `slerp(a,b,t)`, but always chooses the \"short path\" between the rotations represented by `a` and `b`.\n\n#### Matrix algebra\n\n* `mul(mat\u003cT,M,N\u003e a, mat\u003cT,N,P\u003e b) -\u003e mat\u003cT,M,P\u003e` is the [matrix product](https://en.wikipedia.org/wiki/Matrix_multiplication) of matrices `a` and `b`\n** `mul(mat\u003cT,M,N\u003e a, vec\u003cT,N\u003e b) -\u003e vec\u003cT,M\u003e` is the [matrix product](https://en.wikipedia.org/wiki/Matrix_multiplication) of matrix `a` and a column matrix containing the elements of vector `b`\n** `mul(a, b, c)` is shorthand for `mul(mul(a, b), c)`\n\n* `outerprod(vec\u003cT,M\u003e a, vec\u003cT,N\u003e b) -\u003e mat\u003cT,M,N\u003e` is the [outer product](https://en.wikipedia.org/wiki/Outer_product) of vectors `a` and `b`\n\n* `diagonal(mat\u003cT,N,N\u003e a) -\u003e vec\u003cT,N\u003e` is a vector containing the elements along the main diagonal of matrix `a`\n* `trace(mat\u003cT,N,N\u003e a) -\u003e T` is the sum of the elements along the main diagonal of matrix `a`\n\n* `transpose(mat\u003cT,M,N\u003e a) -\u003e mat\u003cT,N,M\u003e` is the [transpose](https://en.wikipedia.org/wiki/Transpose) of matrix `a`\n* `adjugate(mat\u003cT,N,N\u003e a) -\u003e mat\u003cT,N,N\u003e` is the [adjugate or classical adjoint](https://en.wikipedia.org/wiki/Adjugate_matrix) of matrix `a` (the transpose of its cofactor matrix, or the numerator in the expression of its inverse)\n* `comatrix(mat\u003cT,N,N\u003e a) -\u003e mat\u003cT,N,N\u003e` is the [comatrix or cofactor matrix](https://en.wikipedia.org/wiki/Minor_(linear_algebra)#Inverse_of_a_matrix) of matrix `a` (the transpose of its adjugate matrix)\n\n* `determinant(mat\u003cT,N,N\u003e a) -\u003e T` is the [determinant](https://en.wikipedia.org/wiki/Determinant) of matrix `a`\n* `inverse(mat\u003cT,N,N\u003e a) -\u003e mat\u003cT,N,N\u003e` is the [multiplicative inverse](https://en.wikipedia.org/wiki/Multiplicative_inverse) of the [invertible matrix](https://en.wikipedia.org/wiki/Invertible_matrix) `a` (undefined for singular inputs)\n\n#### Component-wise operations\n\nThe unary functions `abs`, `floor`, `ceil`, `exp`, `log`, `log10`, `sqrt`, `sin`, `cos`, `tan`, `asin`, `acos`, `atan`, `sinh`, `cosh`, `tanh`, `round` accept a vector-valued argument and produce a vector-valued result by passing individual elements to the function of the same name in the `std::` namespace, as defined by `\u003ccmath\u003e` or `\u003ccstdlib\u003e`.\n\n```cpp\nfloat4 a {1,-4,9,-16}; // a contains 1,-4,9,-16\nfloat4 b = abs(a);     // b contains 1,4,9,16\nfloat4 c = sqrt(b);    // c contains 1,2,3,4\n```\n\nThe binary functions `fmod`, `pow`, `atan2`, and `copysign` function similarly, except that either argument can be a vector or a scalar.\n\n```cpp\nfloat2 a {5,4}, b {2,3};\nfloat2 c = pow(a, 2);    // c contains 25,16\nfloat2 d = pow(2, b);    // d contains 4,8\nfloat2 e = pow(a, b);    // e contains 25,64\n```\n\nThe binary functions `equal`, `nequal`, `less`, `greater`, `lequal`, and `gequal` apply operators `==`, `!=`, `\u003c`, `\u003e`, `\u003c=` and `\u003e=` respectively in a component-wise fashion, returning a `vec\u003cbool,M\u003e`. As before, either argument can be a vector or a scalar.\n\n```cpp\nint2 a {2,5}, b {3,4};\nbool2 c = less(a,3);    // c contains true, false\nbool2 d = equal(4,b);   // d contains false, true\nbool2 e = greater(a,b); // e contains false, true\n```\n\n`min(a,b) -\u003e vec\u003cT,M\u003e` performs the component-wise selection of lesser elements, as by `a[i] \u003c b[i] ? a[i] : b[i]`. Either argument can be a vector or a scalar.\n\n`max(a,b) -\u003e vec\u003cT,M\u003e` performs the component-wise selection of greater elements, as by `a[i] \u003e b[i] ? a[i] : b[i]`. Either argument can be a vector or a scalar.\n\n`clamp(x,l,h) -\u003e vec\u003cT,M\u003e` performs the component-wise clamping of elements between a low and high boundary, as by `min(max(x,l),h)`. Any argument can be a vector or a scalar.\n\n`select(p,a,b) -\u003e vec\u003cT,M\u003e` performs a component-wise ternary operator, as by `p[i] ? a[i] : b[i]`. Any argument can be a vector or a scalar.\n\n`lerp(a,b,t) -\u003e vec\u003cT,M\u003e` performs a component-wise linear interpolation, as by `a[i]*(1-t[i]) + b[i]*t[i]`. Any argument can be a vector or a scalar.\n\n#### Reductions\n\n* `any(vec\u003cbool,M\u003e a) -\u003e bool` is `true` if any element of the vector `a` is `true`\n* `all(vec\u003cbool,M\u003e a) -\u003e bool` is `true` if all elements of the vector `a` are `true`\n* `sum(vec\u003cT,M\u003e a) -\u003e T` is the sum of all elements in the vector `a`\n* `product(vec\u003cT,M\u003e a) -\u003e T` returns the product of all elements in the vector `a`\n* `minelem(vec\u003cT,M\u003e a) -\u003e T` returns the **value** of the least element in the vector `a`\n* `maxelem(vec\u003cT,M\u003e a) -\u003e T` returns the **value** of the greatest element in the vector `a`\n* `argmin(vec\u003cT,M\u003e a) -\u003e int` returns the **zero-based index** of the least element in the vector `a`\n* `argmax(vec\u003cT,M\u003e a) -\u003e int` returns the **zero-based index** of the greatest element in the vector `a`\n\n#### Comparisons\n\n`compare(a,b)` is conceptually equivalent to `operator \u003c=\u003e` from [C++20](https://en.cppreference.com/w/cpp/language/default_comparisons). It compares two values of equivalent shape and returns a value which supports all six standard comparisons against `0`. It provides the same ordering guarantees as the underlying scalar type. That is, a `vec\u003cint,M\u003e` provides a strong ordering, where a `vec\u003cfloat,M\u003e` provides a partial odering.\n\n## Optional features\n\n#### Type aliases\n\nBy default, `linalg.h` does not define any symbols in the global namespace, and a three-element vector of single-precision floating point values must be spelled `linalg::vec\u003cfloat,3\u003e`. In various libraries and shading languages, such a type might be spelled `float3`, `vec3`, `vec3f`, `point3f`, `simd_float3`, or any one of a hundred other possibilities. `linalg.h` provides a collection of useful aliases in the `linalg::aliases` namespace. If the names specified in this namespace are suitable for a user's purposes, they can quickly be brought into scope as follows:\n\n```cpp\n#include \u003clinalg.h\u003e\nusing namespace linalg::aliases;\n\nfloat3 a_vector;\nfloat4x4 a_matrix;\n```\n\nNote that this **only** brings the type aliases into global scope. The core types and all functions and operator overloads defined by the library remain in `namespace linalg`. \n\nIf the spellings in `namespace linalg::aliases` conflict with other types that have been defined in the global namespace or in other namespaces of interest, the user can choose to omit the `using namespace` directive and instead define their own aliases as desired.\n\n```cpp\n#include \u003clinalg.h\u003e\nusing v3f = linalg::vec\u003cfloat,3\u003e;\nusing m44f = linalg::mat\u003cfloat,4,4\u003e;\n\nv3f a_vector;\nm44f a_matrix;\n```\n\nIt is, of course, always possible to use the core `linalg.h` types directly if operating in an environment where no additional symbols should be defined.\n\n```cpp\n#include \u003clinalg.h\u003e\n\nlinalg::vec\u003cfloat,3\u003e a_vector;\nlinalg::mat\u003cfloat,4,4\u003e a_matrix;\n```\n\nThe set of type aliases defined in `namespace linalg::aliases` is as follows:\n\n* `vec\u003cfloat,M\u003e` aliased to *floatM*, as in: `float1`, `float2`, `float3`, `float4`\n* `vec\u003cdouble,M\u003e` aliased to *doubleM*, as in: `double1`, `double2`, `double3`, `double4`\n* `vec\u003cint,M\u003e` aliased to *intM* as in: `int1`, `int2`, `int3`, `int4`\n* `vec\u003cunsigned,M\u003e` aliased to *uintM* as in: `uint1`, `uint2`, `uint3`, `uint4`\n* `vec\u003cbool,M\u003e` aliased to *boolM* as in: `bool1`, `bool2`, `bool3`, `bool4`\n* `vec\u003cint16_t,M\u003e` aliased to *shortM* as in: `short1`, `short2`, `short3`, `short4`\n* `vec\u003cuint16_t,M\u003e` aliased to *ushortM* as in: `ushort1`, `ushort2`, `ushort3`, `ushort4`\n* `vec\u003cuint8_t,M\u003e` aliased to *byteM* as in: `byte1`, `byte2`, `byte3`, `byte4`\n* `mat\u003cfloat,M,N\u003e` aliased to *floatMxN* as in: `float1x3`, `float3x2`, `float4x4`, etc.\n* `mat\u003cdouble,M,N\u003e` aliased to *doubleMxN* as in: `double1x3`, `double3x2`, `double4x4`, etc.\n* `mat\u003cint,M,N\u003e` aliased to *intMxN* as in: `int1x3`, `int3x2`, `int4x4`, etc.\n* `mat\u003cbool,M,N\u003e` aliased to *boolMxN* as in: `boolx3`, `bool3x2`, `bool4x4`, etc.\n\nAll combinations of up to four elements, rows, or columns are provided.\n\n#### `ostream` overloads\n\nBy default, `linalg.h` does not provide operators for interaction with standard library streams. This is to permit maximum flexibility for users who wish to define their own formatting (with or without delimiters, row versus column major matrices, human-readable precision or round-trip exact). However, as it is often useful to simply be able to show something when writing small programs, we provide some default stream operator overloads which can be brought into scope with:\n\n```cpp\n#include \"linalg.h\"\nusing namespace linalg::ostream_overloads;\n```\n\nThe provided behavior is to output a string using the currently specified stream properties (width, precision, padding, etc) which matches the braced-initialization syntax that could be used to construct that same value, without any extra whitespace.\n\n```cpp\nint3 v {1, 2, 3};\nint2x2 m {{4, 5}, {6, 7}};\nstd::cout \u003c\u003c v \u003c\u003c std::endl; // Prints {1,2,3}\nstd::wcout \u003c\u003c m \u003c\u003c std::endl; // Prints {{4,5},{6,7}}\n```\n\n#### User-defined conversions\n\nA mechanism exists to define automatic conversions between `linalg` and user-provided types. As an example, this mechanism has already been used to defined bidirectional conversions between `linalg::vec\u003cT,M\u003e` and `std::array\u003cT,M\u003e`.\n\n**TODO: Explain `converter\u003cT,U\u003e`**\n\n## Higher order functions\n\n#### `linalg::fold(f, a, b)`\n\n`fold(f, a, b)` is a higher order function which accepts a function of the form `A,B =\u003e A` and repeatedly invokes `a = f(a, element_of_b)` until all elements have been consumed, before returning `a`. It is approximately equal to a [left fold with an initial value](https://en.wikipedia.org/wiki/Fold_(higher-order_function)). When `b` is a `vec\u003cT,M\u003e`, elements are folded from least to greatest index. When `b` is a `mat\u003cT,M,N\u003e`, elements are folded in column-major order.\n\nSee also: [Reductions](#reductions)\n\n#### `linalg::apply(f, a...)`\n\n`apply(f, a...)` is a higher order function which accepts a function of the form `A... =\u003e T` and applies it to component-wise sets of elements from data structures of compatible shape and dimensions. It is approximately equal to a [convolution](https://en.wikipedia.org/wiki/Convolution_(computer_science)) followed by a [map](https://en.wikipedia.org/wiki/Map_(higher-order_function)). The shape of the result (that is, whether it is a scalar, vector, or matrix, and the dimensions thereof) is determined by the arguments. If more than one argument is a non-scalar, the shape of those arguments must agree. Scalars can be freely intermixed with non-scalars, and element types can also be freely mixed. The element type of the returned value is determined by the return type of the provided mapping function `f`. The supported call signatures are enumerated in the following table:\n\n| call             | type of `a`  | type of `b`  | type of `c` | result type  | result elements          |\n|------------------|--------------|--------------|-------------|--------------|--------------------------|\n| `apply(f,a)`     | `A`          |              |             | `T`          | `f(a)`                   |\n| `apply(f,a)`     | `vec\u003cA,M\u003e`   |              |             | `vec\u003cT,M\u003e`   | `f(a[i])...`             |\n| `apply(f,a)`     | `mat\u003cA,M,N\u003e` |              |             | `mat\u003cT,M,N\u003e` | `f(a[j][i])...`          |\n| `apply(f,a,b)`   | `A`          | `B`          |             | `T`          | `f(a, b)...`             |\n| `apply(f,a,b)`   | `A`          | `vec\u003cB,M\u003e`   |             | `vec\u003cT,M\u003e`   | `f(a, b[i])...`          |\n| `apply(f,a,b)`   | `vec\u003cA,M\u003e`   | `B`          |             | `vec\u003cT,M\u003e`   | `f(a[i], b)...`          |\n| `apply(f,a,b)`   | `vec\u003cA,M\u003e`   | `vec\u003cB,M\u003e`   |             | `vec\u003cT,M\u003e`   | `f(a[i], b[i])...`       |\n| `apply(f,a,b)`   | `A`          | `mat\u003cB,M,N\u003e` |             | `mat\u003cT,M,N\u003e` | `f(a, b[j][i])...`       |\n| `apply(f,a,b)`   | `mat\u003cA,M,N\u003e` | `B`          |             | `mat\u003cT,M,N\u003e` | `f(a[j][i], b)...`       |\n| `apply(f,a,b)`   | `mat\u003cA,M,N\u003e` | `mat\u003cB,M,N\u003e` |             | `mat\u003cT,M,N\u003e` | `f(a[j][i], b[j][i])...` |\n| `apply(f,a,b,c)` | `A`          | `B`          | `C`         | `T`          | `f(a, b, c)...`          |\n| `apply(f,a,b,c)` | `A`          | `B`          | `vec\u003cC,M\u003e`  | `vec\u003cT,M\u003e`   | `f(a, b, c[i])...`       |\n| `apply(f,a,b,c)` | `A`          | `vec\u003cB,M\u003e`   | `C`         | `vec\u003cT,M\u003e`   | `f(a, b[i], c)...`       |\n| `apply(f,a,b,c)` | `A`          | `vec\u003cB,M\u003e`   | `vec\u003cC,M\u003e`  | `vec\u003cT,M\u003e`   | `f(a, b[i], c[i])...`    |\n| `apply(f,a,b,c)` | `vec\u003cA,M\u003e`   | `B`          | `C`         | `vec\u003cT,M\u003e`   | `f(a[i], b, c)...`       |\n| `apply(f,a,b,c)` | `vec\u003cA,M\u003e`   | `B`          | `vec\u003cC,M\u003e`  | `vec\u003cT,M\u003e`   | `f(a[i], b, c[i])...`    |\n| `apply(f,a,b,c)` | `vec\u003cA,M\u003e`   | `vec\u003cB,M\u003e`   | `C`         | `vec\u003cT,M\u003e`   | `f(a[i], b[i], c)...`    |\n| `apply(f,a,b,c)` | `vec\u003cA,M\u003e`   | `vec\u003cB,M\u003e`   | `vec\u003cC,M\u003e`  | `vec\u003cT,M\u003e`   | `f(a[i], b[i], c[i])...` |\n\n**TODO: Explain `apply_t\u003cF, A...\u003e` and SFINAE helpers.**\n\nSee also: [Component-wise operations](#component-wise-operations)\n\n## Changes from `v2.1`\n\n#### Improvements in `v2.2`\n\n* `map(a,f)` and `zip(a,b,f)` subsumed by new `apply(f,a...)`\n  * `apply(...)` supports unary, binary, and ternary operations for `vec`\n  * `apply(...)` supports unary and binary operations for `mat` and `quat`\n  * `apply(...)` can also be invoked exclusively with scalars, and supports arbitrary numbers of arguments\n  * `apply(...)` supports mixed element types\n  * Template type alias `apply_t\u003cF,A...\u003e` provides the return type of `apply(f,a...)`\n* `vec\u003cT,1\u003e` and `mat\u003cT,M,1\u003e` specializations are now provided\n* `compare(a,b)` provide three-way comparison between compatible types\n* `clamp(a,b,c)` can be invoked with three distinct (but compatible) types\n* `select(a,b,c)` provides the a component-wise equivalent to `a ? b : c`\n* `lerp(a,b,t)` has been generalized to a component-wise operation where any of `a`, `b`, and `t` can be vectors or scalars\n* User can specialize `converter\u003cT,U\u003e` to enable implicit conversions from `U` to `T`, if either type is a `vec`, `mat`, or `quat`\n  * `identity` is implemented using this facility to serve as an in-library example\n* No undefined behavior according to the C++11 standard\n* Almost all operations which do not internally call `\u003ccmath\u003e` functions are `constexpr`, except for `argmin` and `argmax`\n* No lambdas are used in `linalg.h`, avoiding potential ODR violations\n\n#### Deprecations in `v2.2`\n\n* `operator *` has been deprecated between pairs of matrices.\n  * Call `cmul(...)` if the original, component-wise product was intended\n  * Call `mul(...)` if the algebraic matrix product was intended\n\nYou can `#define LINALG_FORWARD_COMPATIBLE` before including `linalg.h` to remove all deprecated features.\n\n#### Breaking changes in `v2.2-beta`\n\nIt is intended that compatibility will be restored before officially tagging `v2.2`\n\n* `linalg.h` no longer supports Visual Studio 2013. However, it is known to work on GCC 4.9+, Clang 3.5+ in C++11 mode and Visual Studio 2015+.\n* `vec\u003cT,M\u003e` and `mat\u003cT,M,N\u003e` may only be used with a `T` which is an [arithmetic type](https://en.cppreference.com/w/c/language/arithmetic_types)\n  * This requirement will likely be relaxed, but will require specializing some trait type to indicate additional scalar types\n","funding_links":[],"categories":["Math","进程间通信","Maths","[Libraries](#awesome-robotics-libraries)","Mathematics"],"sub_categories":["数学","[Math](#awesome-robotics-libraries)"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsgorsten%2Flinalg","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsgorsten%2Flinalg","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsgorsten%2Flinalg/lists"}