{"id":15031464,"url":"https://github.com/jlogan03/strobe","last_synced_at":"2026-02-26T17:04:07.069Z","repository":{"id":195428217,"uuid":"691801740","full_name":"jlogan03/strobe","owner":"jlogan03","description":"Fast, limited-memory array expressions on the stack in Rust, no-std compatible","archived":false,"fork":false,"pushed_at":"2025-05-19T09:10:46.000Z","size":60,"stargazers_count":27,"open_issues_count":1,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-06-21T10:08:00.284Z","etag":null,"topics":["arrays","math","rust","rustlang"],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jlogan03.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE-APACHE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2023-09-14T23:30:49.000Z","updated_at":"2024-07-29T16:59:53.000Z","dependencies_parsed_at":"2023-12-09T17:24:24.663Z","dependency_job_id":"d374e5e5-e1f3-4dba-a6bf-4aaa8869e022","html_url":"https://github.com/jlogan03/strobe","commit_stats":null,"previous_names":["jlogan03/strobe"],"tags_count":5,"template":false,"template_full_name":null,"purl":"pkg:github/jlogan03/strobe","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jlogan03%2Fstrobe","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jlogan03%2Fstrobe/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jlogan03%2Fstrobe/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jlogan03%2Fstrobe/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jlogan03","download_url":"https://codeload.github.com/jlogan03/strobe/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jlogan03%2Fstrobe/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":261103451,"owners_count":23109932,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","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":["arrays","math","rust","rustlang"],"created_at":"2024-09-24T20:15:44.073Z","updated_at":"2026-02-26T17:04:02.027Z","avatar_url":"https://github.com/jlogan03.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Strobe\nFast, low-memory, elementwise array expressions on the stack.\nCompatible with no-std (and no-alloc) environments.\n\nThis crate provides array expressions of arbitrary depth and executes\nwithout allocation (if an output array is provided) or with a single\nallocation only for the output array.\n\nVectorization over segments of the data is achieved whenever the\ninner function is compatible with the compiler's loop vectorizer\nand matches the available (and enabled) SIMD instruction sets on\nthe target CPU.\n\n## Who is it for?\nIf you're\n* doing multi-step array operations of size \u003e\u003e 64 elements,\n* and can formulate your array expression as a tree,\n* and are bottlenecked on allocation or can't allocate at all,\n* or need concretely bounded memory usage,\n* or are memory _or_ CPU usage constrained,\n* or don't have the standard library,\n* or want to bag a speedup without hand-vectorizing,\n\nthen this may be helpful.\n\n## Who is it _not_ for?\nIf, however, you're\n* doing single-step or small-size array operations,\n* or can't reasonably formulate your expression as a tree,\n* or can get the performance you need from a library with excellent ergonomics, like `ndarray`,\n* or need absolutely the fastest and lowest-memory method possible\n  and are willing and able and have time to hand-vectorize your application,\n\nthen this may not be helpful at all.\n\n# Example: (A - B) * (C + D) with one allocation\n```rust\nuse strobe::{array, add, sub, mul};\n\n// Generate some arrays to operate on\nconst NT: usize = 10_000;\nlet a = vec![1.25_f64; NT];\nlet b = vec![-5.32; NT];\nlet c = vec![1e-3; NT];\nlet d = vec![3.14; NT];\n\n// Associate those arrays with inputs to the expression\nlet an = \u0026mut array(\u0026a);\nlet bn = \u0026mut array(\u0026b);\nlet cn = \u0026mut array(\u0026c);\nlet dn = \u0026mut array(\u0026d);\n\n// Build the expression tree, then evaluate,\n// allocating once for the output array purely for convenience\nlet y = mul(\u0026mut sub(an, bn), \u0026mut add(cn, dn)).eval();\n\n// Check results for consistency\n(0..NT).for_each(|i| { assert_eq!(y[i], (a[i] - b[i]) * (c[i] + d[i]) ) });\n```\n\n# Example: Evaluation with zero allocation\nWhile we use a simple example here, any strobe expression can be\nevaluated into existing storage in this way.\n```rust\nuse strobe::{array, mul};\n\n// Generate some arrays to operate on\nconst NT: usize = 10_000;\nlet a = vec![1.25_f64; NT];\nlet an0 = \u0026mut array(\u0026a);  // Two input nodes from `a`, for brevity\nlet an1 = \u0026mut array(\u0026a);\n\n// Pre-allocate storage\nlet mut y = vec![0.0; NT];\n\n// Build the expression tree, then evaluate into preallocated storage.\nmul(an0, an1).eval_into(\u0026mut y);\n\n// Check results for consistency\n(0..NT).for_each(|i| { assert_eq!(y[i], a[i] * a[i] ) });\n```\n\n# Example: Custom expression nodes\nMany common functions are already implemented. Ones that are not\ncan be assembled using the `unary`, `binary`, `ternary`, and\n`accumulator` functions along with a matching function pointer\nor closure.\n```rust\nuse strobe::{array, unary};\n\nlet x = [0.0_f64, 1.0, 2.0];\nlet mut xn = array(\u0026x);\n\nlet sq_func = |a: \u0026[f64], out: \u0026mut [f64]| { (0..a.len()).for_each(|i| {out[i] = x[i].powi(2)}) };\nlet xsq = unary(\u0026mut xn, \u0026sq_func).eval();\n\n(0..x.len()).for_each(|i| {assert_eq!(x[i] * x[i], xsq[i])});\n```\n\n# Conspicuous Design Decisions and UAQ (Un-Asked Questions)\n* Why not implement the standard num ops?\n    * Because we can't guarantee the lifetime of the returned node will match the lifetime of the references it owns,\n      unless the outside scope is guaranteed to own both the inputs and outputs.\n* Why abandon the more idiomatic functional programming regime at the interface?\n    * Same reason we don't have the standard num ops - unfortunately, this usage breaks lifetime guarantees.\n* Why isn't it panic-never compatible?\n    * In order to guarantee the lengths of the data and eliminate panic branches in slice operations,\n      we would need to use fixed-length input arrays and propagate those lengths with const generics.\n      This would give unpleasant ergonomics and, because array lengths would need to be established at\n      compile time, this would also prevent any useful interlanguage bindings.\n* Why do expressions need to be strict trees?\n    * Because we are strictly on the stack, and we need mutable references to each node in order to use intermediate storage,\n      which we need in order to allow vectorization,\n      and since we can only have one mutable reference to a anything, this naturally produces a tree structure.\n    * _However_ since the input arrays do not need to be mutable, more than one expression node can refer to a given input array,\n      which resolves many (but not all) potential cases where the strict tree structure might prove inadequate.\n* I can hand-vectorize my array operations and do them even faster with even less memory!\n    * Cool! Have fun with that.\n\n\n# License\nLicensed under either of\n\n- Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0)\n- MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)\n\nat your option.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjlogan03%2Fstrobe","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjlogan03%2Fstrobe","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjlogan03%2Fstrobe/lists"}