fastlowess-wasm 0.99.9 β†’ 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,13 +1,20 @@
1
1
  <!-- markdownlint-disable MD024 MD033 -->
2
2
  # LOWESS Project
3
3
 
4
- [![License](https://img.shields.io/badge/license-MIT%2FApache--2.0-blue.svg)](LICENSE-MIT)
5
- [![Docs](https://img.shields.io/badge/docs-readthedocs-blue.svg)](https://lowess.readthedocs.io/)
6
- [![Crates.io](https://img.shields.io/crates/v/lowess.svg)](https://crates.io/crates/lowess)
7
- [![PyPI](https://img.shields.io/pypi/v/fastlowess.svg)](https://pypi.org/project/fastlowess/)
8
- [![Conda](https://anaconda.org/conda-forge/fastlowess/badges/version.svg)](https://anaconda.org/conda-forge/fastlowess)
9
- [![R-universe](https://thisisamirv.r-universe.dev/badges/rfastlowess)](https://thisisamirv.r-universe.dev/rfastlowess)
10
- [![npm](https://img.shields.io/npm/v/fastlowess.svg)](https://www.npmjs.com/package/fastlowess)
4
+ <p align="center">
5
+ <a href="https://crates.io/crates/lowess"><img src="https://img.shields.io/badge/lowess-000000?logo=rust&logoColor=white" alt="lowess"></a>
6
+ <a href="https://crates.io/crates/fastLowess"><img src="https://img.shields.io/badge/fastLowess-000000?logo=rust&logoColor=white" alt="fastLowess"></a>
7
+ <a href="https://pypi.org/project/fastlowess/"><img src="https://img.shields.io/badge/PyPI-3775A9?logo=pypi&logoColor=white" alt="PyPI"></a>
8
+ <a href="https://thisisamirv.r-universe.dev/rfastlowess"><img src="https://img.shields.io/badge/R--universe-276DC3?logo=r&logoColor=white" alt="R-universe"></a>
9
+ <a href="https://www.npmjs.com/package/fastlowess"><img src="https://img.shields.io/badge/npm-CB3837?logo=npm&logoColor=white" alt="npm"></a>
10
+ <a href="https://juliahub.com/ui/Packages/General/fastlowess_jll"><img src="https://img.shields.io/badge/Julia-9558B2?logo=julia&logoColor=white" alt="Julia"></a>
11
+ <a href="https://www.npmjs.com/package/fastlowess-wasm"><img src="https://img.shields.io/badge/WASM-654FF0?logo=webassembly&logoColor=white" alt="WASM"></a>
12
+ <a href="https://github.com/thisisamirv/lowess-project/releases/latest"><img src="https://img.shields.io/badge/C++-00599C?logo=cplusplus&logoColor=white" alt="C++"></a>
13
+ <br>
14
+ <a href="https://anaconda.org/conda-forge/fastlowess"><img src="https://img.shields.io/badge/fastlowess_(Python)-44A833?logo=anaconda&logoColor=white" alt="fastlowess (Python)"></a>
15
+ <a href="https://anaconda.org/conda-forge/libfastlowess"><img src="https://img.shields.io/badge/libfastlowess_(C++)-44A833?logo=anaconda&logoColor=white" alt="libfastlowess (C++)"></a>
16
+ <a href="https://anaconda.org/conda-forge/r-rfastlowess"><img src="https://img.shields.io/badge/rfastlowess_(R)-44A833?logo=anaconda&logoColor=white" alt="rfastlowess (R)"></a>
17
+ </p>
11
18
 
12
19
  <p align="center">
13
20
  <img src="https://raw.githubusercontent.com/thisisamirv/lowess-project/main/dev/logo.png" alt="One LOWESS to Rule Them All" width="400">
@@ -21,14 +28,30 @@ The fastest, most robust, and most feature-complete language-agnostic LOWESS (Lo
21
28
  >
22
29
  > The `lowess-project` contains a complete ecosystem for LOWESS smoothing:
23
30
  >
24
- > - **[`lowess`](https://github.com/thisisamirv/lowess-project/tree/main/crates/lowess)** - Core single-threaded Rust implementation with `no_std` support
25
- > - **[`fastLowess`](https://github.com/thisisamirv/lowess-project/tree/main/crates/fastLowess)** - Parallel CPU and GPU-accelerated Rust wrapper with ndarray integration
26
- > - **[`R bindings`](https://github.com/thisisamirv/lowess-project/tree/main/bindings/r)** - extendr-based R package
27
- > - **[`Python bindings`](https://github.com/thisisamirv/lowess-project/tree/main/bindings/python)** - PyO3-based Python package
28
- > - **[`Julia bindings`](https://github.com/thisisamirv/lowess-project/tree/main/bindings/julia)** - Native Julia package with C FFI
29
- > - **[`JavaScript bindings`](https://github.com/thisisamirv/lowess-project/tree/main/bindings/nodejs)** - Node.js package
30
- > - **[`WebAssembly bindings`](https://github.com/thisisamirv/lowess-project/tree/main/bindings/wasm)** - WASM package
31
- > - **[`C++ bindings`](https://github.com/thisisamirv/lowess-project/tree/main/bindings/cpp)** - Native C++ package with CMake integration
31
+ > - **[`lowess`](https://crates.io/crates/lowess)** - Core single-threaded Rust implementation with `no_std` support
32
+ > - **[`fastLowess`](https://crates.io/crates/fastLowess)** - Parallel CPU and GPU-accelerated Rust wrapper with ndarray integration
33
+ > - **[`R bindings`](https://thisisamirv.r-universe.dev/rfastlowess)** - extendr-based R binding
34
+ > - **[`Python bindings`](https://pypi.org/project/fastlowess/)** - PyO3-based Python binding
35
+ > - **[`Julia bindings`](https://juliahub.com/ui/Packages/General/fastlowess_jll)** - Native Julia binding with C FFI
36
+ > - **[`JavaScript bindings`](https://www.npmjs.com/package/fastlowess)** - Node.js binding
37
+ > - **[`WebAssembly bindings`](https://www.npmjs.com/package/fastlowess-wasm)** - WASM binding
38
+ > - **[`C++ bindings`](https://github.com/thisisamirv/lowess-project/releases/latest)** - Native C++ binding with CMake integration
39
+
40
+ ---
41
+
42
+ ## Installation
43
+
44
+ > [!NOTE]
45
+ >
46
+ > Currently available for R, Python, Rust, Julia, Node.js, WebAssembly, and C++. See [INSTALLATION.md](https://github.com/thisisamirv/lowess-project/blob/main/INSTALLATION.md) for detailed installation instructions.
47
+
48
+ ## Documentation
49
+
50
+ > [!NOTE]
51
+ >
52
+ > ### πŸ“š [View the full documentation](https://lowess.readthedocs.io/)
53
+
54
+ ---
32
55
 
33
56
  ## LOESS vs. LOWESS
34
57
 
@@ -44,38 +67,13 @@ The fastest, most robust, and most feature-complete language-agnostic LOWESS (Lo
44
67
 
45
68
  ---
46
69
 
47
- ## Documentation
48
-
49
- > [!NOTE]
50
- >
51
- > ### πŸ“š [View the full documentation](https://lowess.readthedocs.io/)
52
-
53
70
  ## Why this package?
54
71
 
55
72
  ### Speed
56
73
 
57
- The `lowess` project crushes the competition in terms of speed, wether in single-threaded or multi-threaded parallel execution.
58
-
59
- Speedup relative to Python's `statsmodels.lowess` (higher is better):
60
-
61
- | Category | statsmodels | R (stats) | Serial | Parallel | GPU |
62
- |---------------------------------|-------------|-----------|--------|----------|---------|
63
- | **Clustered** | 163ms | 83Γ— | 203Γ— | **433Γ—** | 32Γ— |
64
- | **Constant Y** | 134ms | 92Γ— | 212Γ— | **410Γ—** | 18Γ— |
65
- | **Delta** (large–none) | 105ms | 2Γ— | 4Γ— | 6Γ— | **16Γ—** |
66
- | **Extreme Outliers** | 489ms | 106Γ— | 201Γ— | **388Γ—** | 29Γ— |
67
- | **Financial** (500–10K) | 106ms | 105Γ— | 252Γ— | **293Γ—** | 12Γ— |
68
- | **Fraction** (0.05–0.67) | 221ms | 104Γ— | 228Γ— | **391Γ—** | 22Γ— |
69
- | **Genomic** (1K–50K) | 1833ms | 7Γ— | 9Γ— | 20Γ— | **95Γ—** |
70
- | **High Noise** | 435ms | 133Γ— | 134Γ— | **375Γ—** | 32Γ— |
71
- | **Iterations** (0–10) | 204ms | 115Γ— | 224Γ— | **386Γ—** | 18Γ— |
72
- | **Scale** (1K–50K) | 1841ms | 264Γ— | 487Γ— | **581Γ—** | 98Γ— |
73
- | **Scientific** (500–10K) | 167ms | 109Γ— | 205Γ— | **314Γ—** | 15Γ— |
74
- | **Scale Large**\* (100K–2M) | β€” | β€” | 1Γ— | **1.4Γ—** | 0.3Γ— |
74
+ The `lowess` project beats the competition in terms of speed, whether in single-threaded or multi-threaded parallel execution. It is on average **200-327x faster** than Python's `statsmodels.lowess` and **2-3x faster** than R's `lowess`.
75
75
 
76
- \*Scale Large benchmarks are relative to Serial (statsmodels cannot handle these sizes)
77
-
78
- *The numbers are the average across a range of scenarios for each category (e.g., Delta from none, to small, medium, and large).*
76
+ For more details on the performance comparison, see the [BENCHMARKS](https://github.com/thisisamirv/lowess-project/blob/main/BENCHMARKS.md) file.
79
77
 
80
78
  ### Robustness
81
79
 
@@ -146,182 +144,6 @@ All implementations are **numerical twins** of R's `lowess`:
146
144
  | **Consistency** | βœ… PERFECT | Multiple scenarios pass with strict tolerance |
147
145
  | **Robustness** | βœ… VERIFIED | Robust smoothing matches R exactly |
148
146
 
149
- ## Installation
150
-
151
- Currently available for R, Python, Julia, and Rust:
152
-
153
- **R** (from R-universe, recommended):
154
-
155
- ```r
156
- install.packages("rfastlowess", repos = "https://thisisamirv.r-universe.dev")
157
- ```
158
-
159
- **Python** (from PyPI):
160
-
161
- ```bash
162
- pip install fastlowess
163
- ```
164
-
165
- Or from conda-forge:
166
-
167
- ```bash
168
- conda install -c conda-forge fastlowess
169
- ```
170
-
171
- **Rust** (lowess, no_std compatible):
172
-
173
- ```toml
174
- [dependencies]
175
- lowess = "0.99"
176
- ```
177
-
178
- **Rust** (fastLowess, parallel + GPU):
179
-
180
- ```toml
181
- [dependencies]
182
- fastLowess = { version = "0.99", features = ["cpu"] }
183
- ```
184
-
185
- **Julia** (from Julia General Registry):
186
-
187
- ```julia
188
- using Pkg
189
- Pkg.add("fastLowess")
190
- ```
191
-
192
- **Node.js** (from npm):
193
-
194
- ```bash
195
- npm install fastlowess
196
- ```
197
-
198
- **WebAssembly** (from npm):
199
-
200
- ```bash
201
- npm install fastlowess-wasm
202
- ```
203
-
204
- Or via CDN:
205
-
206
- ```html
207
- <script type="module">
208
- import init, { smooth } from 'https://unpkg.com/fastlowess-wasm@latest';
209
- await init();
210
- </script>
211
- ```
212
-
213
- **C++** (build from source):
214
-
215
- ```bash
216
- make cpp
217
- # Links against libfastlowess_cpp.so
218
- ```
219
-
220
- ## Quick Example
221
-
222
- **R:**
223
-
224
- ```r
225
- library(rfastlowess)
226
-
227
- x <- c(1, 2, 3, 4, 5)
228
- y <- c(2.0, 4.1, 5.9, 8.2, 9.8)
229
-
230
- model <- Lowess(fraction = 0.5, iterations = 3)
231
- result <- model$fit(x, y)
232
- print(result$y)
233
- ```
234
-
235
- **Python:**
236
-
237
- ```python
238
- import fastlowess as fl
239
- import numpy as np
240
-
241
- x = np.array([1.0, 2.0, 3.0, 4.0, 5.0])
242
- y = np.array([2.0, 4.1, 5.9, 8.2, 9.8])
243
-
244
- result = fl.smooth(x, y, fraction=0.5, iterations=3)
245
- print(result["y"])
246
- ```
247
-
248
- **Rust:**
249
-
250
- ```rust
251
- use lowess::prelude::*;
252
-
253
- let x = vec![1.0, 2.0, 3.0, 4.0, 5.0];
254
- let y = vec![2.0, 4.1, 5.9, 8.2, 9.8];
255
-
256
- let model = Lowess::new()
257
- .fraction(0.5)
258
- .iterations(3)
259
- .adapter(Batch)
260
- .build()?;
261
-
262
- let result = model.fit(&x, &y)?;
263
- println!("{}", result);
264
- ```
265
-
266
- **Julia:**
267
-
268
- ```julia
269
- using fastlowess
270
-
271
- x = [1.0, 2.0, 3.0, 4.0, 5.0]
272
- y = [2.0, 4.1, 5.9, 8.2, 9.8]
273
-
274
- result = fit(Lowess(fraction=0.5, iterations=3), x, y)
275
- println(result.y)
276
- ```
277
-
278
- **Node.js:**
279
-
280
- ```javascript
281
- const { Lowess } = require('fastlowess');
282
-
283
- const x = [1.0, 2.0, 3.0, 4.0, 5.0];
284
- const y = [2.0, 4.1, 5.9, 8.2, 9.8];
285
-
286
- const model = new Lowess({ fraction: 0.5, iterations: 3 });
287
- const result = model.fit(x, y);
288
- console.log(result.y);
289
- ```
290
-
291
- **WebAssembly:**
292
-
293
- ```javascript
294
- import init, { smooth } from 'fastlowess-wasm';
295
-
296
- await init();
297
-
298
- const x = new Float64Array([1.0, 2.0, 3.0, 4.0, 5.0]);
299
- const y = new Float64Array([2.0, 4.1, 5.9, 8.2, 9.8]);
300
-
301
- const result = smooth(x, y, { fraction: 0.5, iterations: 3 });
302
- console.log(result.y);
303
- ```
304
-
305
- **C++:**
306
-
307
- ```cpp
308
- #include <fastlowess.hpp>
309
-
310
- std::vector<double> x = {1.0, 2.0, 3.0, 4.0, 5.0};
311
- std::vector<double> y = {2.0, 4.1, 5.9, 8.2, 9.8};
312
-
313
- fastlowess::LowessOptions options;
314
- options.fraction = 0.5;
315
- options.iterations = 3;
316
-
317
- fastlowess::Lowess model(options);
318
- auto result = model.fit(x, y);
319
-
320
- for (double val : result.y_vector()) std::cout << val << " ";
321
- ```
322
-
323
- ---
324
-
325
147
  ## API Reference
326
148
 
327
149
  **R:**
@@ -346,13 +168,29 @@ Lowess(
346
168
  auto_converge = 1e-4,
347
169
  parallel = TRUE
348
170
  )$fit(x, y)
171
+
172
+ # Result structure:
173
+ result$x,
174
+ result$y,
175
+ result$standard_errors,
176
+ result$confidence_lower,
177
+ result$confidence_upper,
178
+ result$prediction_lower,
179
+ result$prediction_upper,
180
+ result$residuals,
181
+ result$robustness_weights,
182
+ result$diagnostics,
183
+ result$iterations_used,
184
+ result$fraction_used,
185
+ result$cv_scores
349
186
  ```
350
187
 
351
188
  **Python:**
352
189
 
353
190
  ```python
354
- fastlowess.smooth(
355
- x, y,
191
+ from fastlowess import Lowess
192
+
193
+ model = Lowess(
356
194
  fraction=0.5,
357
195
  iterations=3,
358
196
  delta=0.01,
@@ -371,16 +209,32 @@ fastlowess.smooth(
371
209
  auto_converge=1e-4,
372
210
  parallel=True
373
211
  )
212
+ result = model.fit(x, y)
213
+
214
+ # Result structure:
215
+ result.x,
216
+ result.y,
217
+ result.standard_errors,
218
+ result.confidence_lower,
219
+ result.confidence_upper,
220
+ result.prediction_lower,
221
+ result.prediction_upper,
222
+ result.residuals,
223
+ result.robustness_weights,
224
+ result.diagnostics,
225
+ result.iterations_used,
226
+ result.fraction_used,
227
+ result.cv_scores
374
228
  ```
375
229
 
376
230
  **Rust:**
377
231
 
378
232
  ```rust
379
233
  Lowess::new()
380
- .fraction(0.5) // Smoothing span (0, 1]
381
- .iterations(3) // Robustness iterations
382
- .delta(0.01) // Interpolation threshold
383
- .weight_function(Tricube) // Kernel selection
234
+ .fraction(0.5)
235
+ .iterations(3)
236
+ .delta(0.01)
237
+ .weight_function(Tricube)
384
238
  .robustness_method(Bisquare)
385
239
  .zero_weight_fallback(UseLocalMean)
386
240
  .boundary_policy(Extend)
@@ -391,10 +245,29 @@ Lowess::new()
391
245
  .return_robustness_weights()
392
246
  .cross_validate(KFold(5, &[0.3, 0.5, 0.7]).seed(123))
393
247
  .auto_converge(1e-4)
394
- .adapter(Batch) // or Streaming, Online
248
+ .adapter(Batch)
395
249
  .parallel(true) // fastLowess only
396
250
  .backend(CPU) // fastLowess only: CPU or GPU
397
251
  .build()?;
252
+
253
+ let result = model.fit(x, y);
254
+
255
+ // Result structure:
256
+ pub struct LowessResult<T> {
257
+ pub x: Vec<T>, // Sorted x values
258
+ pub y: Vec<T>, // Smoothed y values
259
+ pub standard_errors: Option<Vec<T>>,
260
+ pub confidence_lower: Option<Vec<T>>,
261
+ pub confidence_upper: Option<Vec<T>>,
262
+ pub prediction_lower: Option<Vec<T>>,
263
+ pub prediction_upper: Option<Vec<T>>,
264
+ pub residuals: Option<Vec<T>>,
265
+ pub robustness_weights: Option<Vec<T>>,
266
+ pub diagnostics: Option<Diagnostics<T>>,
267
+ pub iterations_used: Option<usize>,
268
+ pub fraction_used: T,
269
+ pub cv_scores: Option<Vec<T>>,
270
+ }
398
271
  ```
399
272
 
400
273
  **Julia:**
@@ -419,6 +292,21 @@ Lowess(;
419
292
  auto_converge=NaN,
420
293
  parallel=true
421
294
  )
295
+
296
+ # Result structure:
297
+ result.x,
298
+ result.y,
299
+ result.standard_errors,
300
+ result.confidence_lower,
301
+ result.confidence_upper,
302
+ result.prediction_lower,
303
+ result.prediction_upper,
304
+ result.residuals,
305
+ result.robustness_weights,
306
+ result.diagnostics,
307
+ result.iterations_used,
308
+ result.fraction_used,
309
+ result.cv_scores
422
310
  ```
423
311
 
424
312
  **Node.js:**
@@ -443,6 +331,21 @@ new Lowess({
443
331
  autoConverge: 1e-4,
444
332
  parallel: true
445
333
  }).fit(x, y)
334
+
335
+ // Result structure:
336
+ result.x,
337
+ result.y,
338
+ result.standardErrors,
339
+ result.confidenceLower,
340
+ result.confidenceUpper,
341
+ result.predictionLower,
342
+ result.predictionUpper,
343
+ result.residuals,
344
+ result.robustnessWeights,
345
+ result.diagnostics,
346
+ result.iterationsUsed,
347
+ result.fractionUsed,
348
+ result.cvScores
446
349
  ```
447
350
 
448
351
  **WebAssembly:**
@@ -464,8 +367,24 @@ smooth(x, y, {
464
367
  cvFractions: [0.3, 0.5, 0.7],
465
368
  cvMethod: "kfold",
466
369
  cvK: 5,
467
- autoConverge: 1e-4
370
+ autoConverge: 1e-4,
371
+ parallel: true
468
372
  })
373
+
374
+ // Result structure:
375
+ result.x,
376
+ result.y,
377
+ result.standardErrors,
378
+ result.confidenceLower,
379
+ result.confidenceUpper,
380
+ result.predictionLower,
381
+ result.predictionUpper,
382
+ result.residuals,
383
+ result.robustnessWeights,
384
+ result.diagnostics,
385
+ result.iterationsUsed,
386
+ result.fractionUsed,
387
+ result.cvScores
469
388
  ```
470
389
 
471
390
  **C++:**
@@ -492,98 +411,21 @@ options.parallel = true;
492
411
 
493
412
  fastlowess::Lowess model(options);
494
413
  auto result = model.fit(x, y);
495
- ```
496
-
497
- ## Result Structure
498
414
 
499
- **R:**
500
-
501
- ```r
502
- result$x, result$y, result$standard_errors
503
- result$confidence_lower, result$confidence_upper
504
- result$prediction_lower, result$prediction_upper
505
- result$residuals, result$robustness_weights
506
- result$diagnostics, result$iterations_used
507
- result$fraction_used, result$cv_scores
508
- ```
509
-
510
- **Python:**
511
-
512
- ```python
513
- result.x, result.y, result.standard_errors
514
- result.confidence_lower, result.confidence_upper
515
- result.prediction_lower, result.prediction_upper
516
- result.residuals, result.robustness_weights
517
- result.diagnostics, result.iterations_used
518
- result.fraction_used, result.cv_scores
519
- ```
520
-
521
- **Rust:**
522
-
523
- ```rust
524
- pub struct LowessResult<T> {
525
- pub x: Vec<T>, // Sorted x values
526
- pub y: Vec<T>, // Smoothed y values
527
- pub standard_errors: Option<Vec<T>>,
528
- pub confidence_lower: Option<Vec<T>>,
529
- pub confidence_upper: Option<Vec<T>>,
530
- pub prediction_lower: Option<Vec<T>>,
531
- pub prediction_upper: Option<Vec<T>>,
532
- pub residuals: Option<Vec<T>>,
533
- pub robustness_weights: Option<Vec<T>>,
534
- pub diagnostics: Option<Diagnostics<T>>,
535
- pub iterations_used: Option<usize>,
536
- pub fraction_used: T,
537
- pub cv_scores: Option<Vec<T>>,
538
- }
539
- ```
540
-
541
- **Julia:**
542
-
543
- ```julia
544
- result.x, result.y, result.standard_errors
545
- result.confidence_lower, result.confidence_upper
546
- result.prediction_lower, result.prediction_upper
547
- result.residuals, result.robustness_weights
548
- result.diagnostics, result.iterations_used
549
- result.fraction_used
550
- ```
551
-
552
- **Node.js:**
553
-
554
- ```javascript
555
- result.x, result.y, result.standardErrors
556
- result.confidenceLower, result.confidenceUpper
557
- result.predictionLower, result.predictionUpper
558
- result.residuals, result.robustnessWeights
559
- result.diagnostics, result.iterationsUsed
560
- result.fractionUsed, result.cvScores
561
- ```
562
-
563
- **WebAssembly:**
564
-
565
- ```javascript
566
- result.x, result.y, result.standardErrors
567
- result.confidenceLower, result.confidenceUpper
568
- result.predictionLower, result.predictionUpper
569
- result.residuals, result.robustnessWeights
570
- result.diagnostics, result.iterationsUsed
571
- result.fractionUsed, result.cvScores
572
- ```
573
-
574
- **C++:**
575
-
576
- ```cpp
577
- result.y_vector() // std::vector<double>
578
- result.confidence_lower() // std::vector<double>
579
- result.confidence_upper() // std::vector<double>
580
- result.prediction_lower() // std::vector<double>
581
- result.prediction_upper() // std::vector<double>
582
- result.residuals() // std::vector<double>
583
- result.robustness_weights() // std::vector<double>
584
- result.diagnostics() // Diagnostics struct
585
- result.iterations_used() // size_t
586
- result.fraction_used() // double
415
+ // Result structure:
416
+ result.x_vector(),
417
+ result.y_vector(),
418
+ result.standard_errors(),
419
+ result.confidence_lower(),
420
+ result.confidence_upper(),
421
+ result.prediction_lower(),
422
+ result.prediction_upper(),
423
+ result.residuals(),
424
+ result.robustness_weights(),
425
+ result.diagnostics(),
426
+ result.iterations_used(),
427
+ result.fraction_used(),
428
+ result.cv_scores()
587
429
  ```
588
430
 
589
431
  ---
@@ -594,17 +436,7 @@ Contributions are welcome! Please see the [CONTRIBUTING.md](https://github.com/t
594
436
 
595
437
  ## License
596
438
 
597
- Licensed under either of:
598
-
599
- - Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or <https://www.apache.org/licenses/LICENSE-2.0>)
600
- - MIT license ([LICENSE-MIT](LICENSE-MIT) or <https://opensource.org/licenses/MIT>)
601
-
602
- at your option.
603
-
604
- ## References
605
-
606
- - Cleveland, W.S. (1979). "Robust Locally Weighted Regression and Smoothing Scatterplots". *JASA*.
607
- - Cleveland, W.S. (1981). "LOWESS: A Program for Smoothing Scatterplots". *The American Statistician*.
439
+ Licensed under [MIT](https://github.com/thisisamirv/lowess-project/blob/main/LICENSE-MIT) or [Apache-2.0](https://github.com/thisisamirv/lowess-project/blob/main/LICENSE-APACHE).
608
440
 
609
441
  ## Citation
610
442
 
@@ -36,21 +36,43 @@ export class LowessResultWasm {
36
36
  readonly y: Float64Array;
37
37
  }
38
38
 
39
+ /**
40
+ * Online LOWESS smoother.
41
+ */
39
42
  export class OnlineLowessWasm {
40
43
  free(): void;
41
44
  [Symbol.dispose](): void;
45
+ /**
46
+ * Create a new online smoother.
47
+ */
42
48
  constructor(options: any, online_opts: any);
43
49
  update(x: number, y: number): number | undefined;
44
50
  }
45
51
 
52
+ /**
53
+ * Streaming LOWESS smoother.
54
+ */
46
55
  export class StreamingLowessWasm {
47
56
  free(): void;
48
57
  [Symbol.dispose](): void;
49
58
  finalize(): LowessResultWasm;
59
+ /**
60
+ * Create a new streaming smoother.
61
+ */
50
62
  constructor(options: any, streaming_opts: any);
51
63
  processChunk(x: Float64Array, y: Float64Array): LowessResultWasm;
52
64
  }
53
65
 
66
+ export function init_panic_hook(): void;
67
+
68
+ /**
69
+ * Fit the LOWESS model to data.
70
+ *
71
+ * @param {Float64Array} x - X coordinates.
72
+ * @param {Float64Array} y - Y coordinates.
73
+ * @param {any} [options] - Configuration object.
74
+ * @returns {LowessResultWasm} The result of the smoothing.
75
+ */
54
76
  export function smooth(x: Float64Array, y: Float64Array, options: any): LowessResultWasm;
55
77
 
56
78
  export type InitInput = RequestInfo | URL | Response | BufferSource | WebAssembly.Module;
@@ -94,11 +116,13 @@ export interface InitOutput {
94
116
  readonly streaminglowesswasm_finalize: (a: number) => [number, number, number];
95
117
  readonly streaminglowesswasm_new: (a: any, b: any) => [number, number, number];
96
118
  readonly streaminglowesswasm_processChunk: (a: number, b: any, c: any) => [number, number, number];
119
+ readonly init_panic_hook: () => void;
97
120
  readonly __wbindgen_malloc: (a: number, b: number) => number;
98
121
  readonly __wbindgen_realloc: (a: number, b: number, c: number, d: number) => number;
99
122
  readonly __wbindgen_exn_store: (a: number) => void;
100
123
  readonly __externref_table_alloc: () => number;
101
124
  readonly __wbindgen_externrefs: WebAssembly.Table;
125
+ readonly __wbindgen_free: (a: number, b: number, c: number) => void;
102
126
  readonly __externref_table_dealloc: (a: number) => void;
103
127
  readonly __wbindgen_start: () => void;
104
128
  }
@@ -224,6 +224,9 @@ export class LowessResultWasm {
224
224
  }
225
225
  if (Symbol.dispose) LowessResultWasm.prototype[Symbol.dispose] = LowessResultWasm.prototype.free;
226
226
 
227
+ /**
228
+ * Online LOWESS smoother.
229
+ */
227
230
  export class OnlineLowessWasm {
228
231
  __destroy_into_raw() {
229
232
  const ptr = this.__wbg_ptr;
@@ -236,6 +239,7 @@ export class OnlineLowessWasm {
236
239
  wasm.__wbg_onlinelowesswasm_free(ptr, 0);
237
240
  }
238
241
  /**
242
+ * Create a new online smoother.
239
243
  * @param {any} options
240
244
  * @param {any} online_opts
241
245
  */
@@ -263,6 +267,9 @@ export class OnlineLowessWasm {
263
267
  }
264
268
  if (Symbol.dispose) OnlineLowessWasm.prototype[Symbol.dispose] = OnlineLowessWasm.prototype.free;
265
269
 
270
+ /**
271
+ * Streaming LOWESS smoother.
272
+ */
266
273
  export class StreamingLowessWasm {
267
274
  __destroy_into_raw() {
268
275
  const ptr = this.__wbg_ptr;
@@ -285,6 +292,7 @@ export class StreamingLowessWasm {
285
292
  return LowessResultWasm.__wrap(ret[0]);
286
293
  }
287
294
  /**
295
+ * Create a new streaming smoother.
288
296
  * @param {any} options
289
297
  * @param {any} streaming_opts
290
298
  */
@@ -312,7 +320,17 @@ export class StreamingLowessWasm {
312
320
  }
313
321
  if (Symbol.dispose) StreamingLowessWasm.prototype[Symbol.dispose] = StreamingLowessWasm.prototype.free;
314
322
 
323
+ export function init_panic_hook() {
324
+ wasm.init_panic_hook();
325
+ }
326
+
315
327
  /**
328
+ * Fit the LOWESS model to data.
329
+ *
330
+ * @param {Float64Array} x - X coordinates.
331
+ * @param {Float64Array} y - Y coordinates.
332
+ * @param {any} [options] - Configuration object.
333
+ * @returns {LowessResultWasm} The result of the smoothing.
316
334
  * @param {Float64Array} x
317
335
  * @param {Float64Array} y
318
336
  * @param {any} options
@@ -329,19 +347,65 @@ export function smooth(x, y, options) {
329
347
  function __wbg_get_imports() {
330
348
  const import0 = {
331
349
  __proto__: null,
350
+ __wbg_Error_8c4e43fe74559d73: function(arg0, arg1) {
351
+ const ret = Error(getStringFromWasm0(arg0, arg1));
352
+ return ret;
353
+ },
354
+ __wbg_Number_04624de7d0e8332d: function(arg0) {
355
+ const ret = Number(arg0);
356
+ return ret;
357
+ },
358
+ __wbg___wbindgen_bigint_get_as_i64_8fcf4ce7f1ca72a2: function(arg0, arg1) {
359
+ const v = arg1;
360
+ const ret = typeof(v) === 'bigint' ? v : undefined;
361
+ getDataViewMemory0().setBigInt64(arg0 + 8 * 1, isLikeNone(ret) ? BigInt(0) : ret, true);
362
+ getDataViewMemory0().setInt32(arg0 + 4 * 0, !isLikeNone(ret), true);
363
+ },
332
364
  __wbg___wbindgen_boolean_get_bbbb1c18aa2f5e25: function(arg0) {
333
365
  const v = arg0;
334
366
  const ret = typeof(v) === 'boolean' ? v : undefined;
335
367
  return isLikeNone(ret) ? 0xFFFFFF : ret ? 1 : 0;
336
368
  },
369
+ __wbg___wbindgen_debug_string_0bc8482c6e3508ae: function(arg0, arg1) {
370
+ const ret = debugString(arg1);
371
+ const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
372
+ const len1 = WASM_VECTOR_LEN;
373
+ getDataViewMemory0().setInt32(arg0 + 4 * 1, len1, true);
374
+ getDataViewMemory0().setInt32(arg0 + 4 * 0, ptr1, true);
375
+ },
376
+ __wbg___wbindgen_in_47fa6863be6f2f25: function(arg0, arg1) {
377
+ const ret = arg0 in arg1;
378
+ return ret;
379
+ },
380
+ __wbg___wbindgen_is_bigint_31b12575b56f32fc: function(arg0) {
381
+ const ret = typeof(arg0) === 'bigint';
382
+ return ret;
383
+ },
384
+ __wbg___wbindgen_is_function_0095a73b8b156f76: function(arg0) {
385
+ const ret = typeof(arg0) === 'function';
386
+ return ret;
387
+ },
337
388
  __wbg___wbindgen_is_null_ac34f5003991759a: function(arg0) {
338
389
  const ret = arg0 === null;
339
390
  return ret;
340
391
  },
392
+ __wbg___wbindgen_is_object_5ae8e5880f2c1fbd: function(arg0) {
393
+ const val = arg0;
394
+ const ret = typeof(val) === 'object' && val !== null;
395
+ return ret;
396
+ },
341
397
  __wbg___wbindgen_is_undefined_9e4d92534c42d778: function(arg0) {
342
398
  const ret = arg0 === undefined;
343
399
  return ret;
344
400
  },
401
+ __wbg___wbindgen_jsval_eq_11888390b0186270: function(arg0, arg1) {
402
+ const ret = arg0 === arg1;
403
+ return ret;
404
+ },
405
+ __wbg___wbindgen_jsval_loose_eq_9dd77d8cd6671811: function(arg0, arg1) {
406
+ const ret = arg0 == arg1;
407
+ return ret;
408
+ },
345
409
  __wbg___wbindgen_number_get_8ff4255516ccad3e: function(arg0, arg1) {
346
410
  const obj = arg1;
347
411
  const ret = typeof(obj) === 'number' ? obj : undefined;
@@ -359,10 +423,25 @@ function __wbg_get_imports() {
359
423
  __wbg___wbindgen_throw_be289d5034ed271b: function(arg0, arg1) {
360
424
  throw new Error(getStringFromWasm0(arg0, arg1));
361
425
  },
362
- __wbg_from_bddd64e7d5ff6941: function(arg0) {
363
- const ret = Array.from(arg0);
426
+ __wbg_call_389efe28435a9388: function() { return handleError(function (arg0, arg1) {
427
+ const ret = arg0.call(arg1);
428
+ return ret;
429
+ }, arguments); },
430
+ __wbg_done_57b39ecd9addfe81: function(arg0) {
431
+ const ret = arg0.done;
364
432
  return ret;
365
433
  },
434
+ __wbg_error_7534b8e9a36f1ab4: function(arg0, arg1) {
435
+ let deferred0_0;
436
+ let deferred0_1;
437
+ try {
438
+ deferred0_0 = arg0;
439
+ deferred0_1 = arg1;
440
+ console.error(getStringFromWasm0(arg0, arg1));
441
+ } finally {
442
+ wasm.__wbindgen_free(deferred0_0, deferred0_1, 1);
443
+ }
444
+ },
366
445
  __wbg_get_9b94d73e6221f75c: function(arg0, arg1) {
367
446
  const ret = arg0[arg1 >>> 0];
368
447
  return ret;
@@ -371,6 +450,46 @@ function __wbg_get_imports() {
371
450
  const ret = Reflect.get(arg0, arg1);
372
451
  return ret;
373
452
  }, arguments); },
453
+ __wbg_get_with_ref_key_1dc361bd10053bfe: function(arg0, arg1) {
454
+ const ret = arg0[arg1];
455
+ return ret;
456
+ },
457
+ __wbg_instanceof_ArrayBuffer_c367199e2fa2aa04: function(arg0) {
458
+ let result;
459
+ try {
460
+ result = arg0 instanceof ArrayBuffer;
461
+ } catch (_) {
462
+ result = false;
463
+ }
464
+ const ret = result;
465
+ return ret;
466
+ },
467
+ __wbg_instanceof_Uint8Array_9b9075935c74707c: function(arg0) {
468
+ let result;
469
+ try {
470
+ result = arg0 instanceof Uint8Array;
471
+ } catch (_) {
472
+ result = false;
473
+ }
474
+ const ret = result;
475
+ return ret;
476
+ },
477
+ __wbg_isArray_d314bb98fcf08331: function(arg0) {
478
+ const ret = Array.isArray(arg0);
479
+ return ret;
480
+ },
481
+ __wbg_isSafeInteger_bfbc7332a9768d2a: function(arg0) {
482
+ const ret = Number.isSafeInteger(arg0);
483
+ return ret;
484
+ },
485
+ __wbg_iterator_6ff6560ca1568e55: function() {
486
+ const ret = Symbol.iterator;
487
+ return ret;
488
+ },
489
+ __wbg_length_32ed9a279acd054c: function(arg0) {
490
+ const ret = arg0.length;
491
+ return ret;
492
+ },
374
493
  __wbg_length_35a7bace40f36eac: function(arg0) {
375
494
  const ret = arg0.length;
376
495
  return ret;
@@ -379,9 +498,39 @@ function __wbg_get_imports() {
379
498
  const ret = arg0.length;
380
499
  return ret;
381
500
  },
501
+ __wbg_new_8a6f238a6ece86ea: function() {
502
+ const ret = new Error();
503
+ return ret;
504
+ },
505
+ __wbg_new_dd2b680c8bf6ae29: function(arg0) {
506
+ const ret = new Uint8Array(arg0);
507
+ return ret;
508
+ },
509
+ __wbg_next_3482f54c49e8af19: function() { return handleError(function (arg0) {
510
+ const ret = arg0.next();
511
+ return ret;
512
+ }, arguments); },
513
+ __wbg_next_418f80d8f5303233: function(arg0) {
514
+ const ret = arg0.next;
515
+ return ret;
516
+ },
382
517
  __wbg_prototypesetcall_aefe6319f589ab4b: function(arg0, arg1, arg2) {
383
518
  Float64Array.prototype.set.call(getArrayF64FromWasm0(arg0, arg1), arg2);
384
519
  },
520
+ __wbg_prototypesetcall_bdcdcc5842e4d77d: function(arg0, arg1, arg2) {
521
+ Uint8Array.prototype.set.call(getArrayU8FromWasm0(arg0, arg1), arg2);
522
+ },
523
+ __wbg_stack_0ed75d68575b0f3c: function(arg0, arg1) {
524
+ const ret = arg1.stack;
525
+ const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
526
+ const len1 = WASM_VECTOR_LEN;
527
+ getDataViewMemory0().setInt32(arg0 + 4 * 1, len1, true);
528
+ getDataViewMemory0().setInt32(arg0 + 4 * 0, ptr1, true);
529
+ },
530
+ __wbg_value_0546255b415e96c1: function(arg0) {
531
+ const ret = arg0.value;
532
+ return ret;
533
+ },
385
534
  __wbindgen_cast_0000000000000001: function(arg0, arg1) {
386
535
  // Cast intrinsic for `Ref(Slice(F64)) -> NamedExternref("Float64Array")`.
387
536
  const ret = getArrayF64FromWasm0(arg0, arg1);
@@ -392,6 +541,11 @@ function __wbg_get_imports() {
392
541
  const ret = getStringFromWasm0(arg0, arg1);
393
542
  return ret;
394
543
  },
544
+ __wbindgen_cast_0000000000000003: function(arg0) {
545
+ // Cast intrinsic for `U64 -> Externref`.
546
+ const ret = BigInt.asUintN(64, arg0);
547
+ return ret;
548
+ },
395
549
  __wbindgen_init_externref_table: function() {
396
550
  const table = wasm.__wbindgen_externrefs;
397
551
  const offset = table.grow(4);
@@ -427,11 +581,81 @@ function addToExternrefTable0(obj) {
427
581
  return idx;
428
582
  }
429
583
 
584
+ function debugString(val) {
585
+ // primitive types
586
+ const type = typeof val;
587
+ if (type == 'number' || type == 'boolean' || val == null) {
588
+ return `${val}`;
589
+ }
590
+ if (type == 'string') {
591
+ return `"${val}"`;
592
+ }
593
+ if (type == 'symbol') {
594
+ const description = val.description;
595
+ if (description == null) {
596
+ return 'Symbol';
597
+ } else {
598
+ return `Symbol(${description})`;
599
+ }
600
+ }
601
+ if (type == 'function') {
602
+ const name = val.name;
603
+ if (typeof name == 'string' && name.length > 0) {
604
+ return `Function(${name})`;
605
+ } else {
606
+ return 'Function';
607
+ }
608
+ }
609
+ // objects
610
+ if (Array.isArray(val)) {
611
+ const length = val.length;
612
+ let debug = '[';
613
+ if (length > 0) {
614
+ debug += debugString(val[0]);
615
+ }
616
+ for(let i = 1; i < length; i++) {
617
+ debug += ', ' + debugString(val[i]);
618
+ }
619
+ debug += ']';
620
+ return debug;
621
+ }
622
+ // Test for built-in
623
+ const builtInMatches = /\[object ([^\]]+)\]/.exec(toString.call(val));
624
+ let className;
625
+ if (builtInMatches && builtInMatches.length > 1) {
626
+ className = builtInMatches[1];
627
+ } else {
628
+ // Failed to match the standard '[object ClassName]'
629
+ return toString.call(val);
630
+ }
631
+ if (className == 'Object') {
632
+ // we're a user defined class or Object
633
+ // JSON.stringify avoids problems with cycles, and is generally much
634
+ // easier than looping through ownProperties of `val`.
635
+ try {
636
+ return 'Object(' + JSON.stringify(val) + ')';
637
+ } catch (_) {
638
+ return 'Object';
639
+ }
640
+ }
641
+ // errors
642
+ if (val instanceof Error) {
643
+ return `${val.name}: ${val.message}\n${val.stack}`;
644
+ }
645
+ // TODO we could test for more things here, like `Set`s and `Map`s.
646
+ return className;
647
+ }
648
+
430
649
  function getArrayF64FromWasm0(ptr, len) {
431
650
  ptr = ptr >>> 0;
432
651
  return getFloat64ArrayMemory0().subarray(ptr / 8, ptr / 8 + len);
433
652
  }
434
653
 
654
+ function getArrayU8FromWasm0(ptr, len) {
655
+ ptr = ptr >>> 0;
656
+ return getUint8ArrayMemory0().subarray(ptr / 1, ptr / 1 + len);
657
+ }
658
+
435
659
  let cachedDataViewMemory0 = null;
436
660
  function getDataViewMemory0() {
437
661
  if (cachedDataViewMemory0 === null || cachedDataViewMemory0.buffer.detached === true || (cachedDataViewMemory0.buffer.detached === undefined && cachedDataViewMemory0.buffer !== wasm.memory.buffer)) {
Binary file
package/package.json CHANGED
@@ -5,7 +5,7 @@
5
5
  "Amir Valizadeh <thisisamirv@gmail.com>"
6
6
  ],
7
7
  "description": "High-performance LOWESS (Locally Weighted Scatterplot Smoothing)",
8
- "version": "0.99.9",
8
+ "version": "1.0.0",
9
9
  "license": "MIT OR Apache-2.0",
10
10
  "repository": {
11
11
  "type": "git",