Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .Rbuildignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,7 @@
^renv\.lock$
^.*\.Rproj$
^\.Rproj\.user$
^\.github$
^README\.Rmd$
^.*\.Rcheck$
^.*\.tar\.gz$
49 changes: 49 additions & 0 deletions .github/workflows/R-CMD-check.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# Based on the standard workflow from r-lib/actions.
on:
push:
branches: [master]
pull_request:
workflow_dispatch:

name: R-CMD-check

permissions: read-all

jobs:
R-CMD-check:
runs-on: ${{ matrix.config.os }}
name: ${{ matrix.config.os }} (R ${{ matrix.config.r }})

strategy:
fail-fast: false
matrix:
config:
- {os: macos-latest, r: "release"}
- {os: windows-latest, r: "release"}
- {os: ubuntu-latest, r: "devel", http-user-agent: "release"}
- {os: ubuntu-latest, r: "release"}
- {os: ubuntu-latest, r: "oldrel-1"}

env:
GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }}
R_KEEP_PKG_SOURCE: yes

steps:
- uses: actions/checkout@v6

- uses: r-lib/actions/setup-pandoc@v2

- uses: r-lib/actions/setup-r@v2
with:
r-version: ${{ matrix.config.r }}
http-user-agent: ${{ matrix.config.http-user-agent }}

- uses: r-lib/actions/setup-r-dependencies@v2
with:
extra-packages: any::rcmdcheck
needs: check

- uses: r-lib/actions/check-r-package@v2
with:
upload-snapshots: true
build_args: 'c("--no-manual", "--compact-vignettes=gs+qpdf")'
114 changes: 114 additions & 0 deletions README.Rmd
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
---
output: github_document
---

<!-- README.md is generated from README.Rmd. Please edit that file. -->

```{r, include = FALSE}
knitr::opts_chunk$set(
collapse = TRUE,
comment = "#>",
fig.path = "man/figures/README-",
out.width = "100%"
)
```

# numops

<!-- badges: start -->
[![R-CMD-check](https://github.com/Macosso/numops/actions/workflows/R-CMD-check.yaml/badge.svg)](https://github.com/Macosso/numops/actions/workflows/R-CMD-check.yaml)
<!-- badges: end -->

numops provides small, dependency-free numerical operations for vectors,
matrices, and arrays. It collects common tasks that otherwise require repeated
base R expressions and gives them consistent validation, scalar recycling, and
shape-preserving behavior.

## Installation

You can install the development version of numops from
[GitHub](https://github.com/Macosso/numops) with:

```r
# install.packages("pak")
pak::pak("Macosso/numops")
```

## Overview

| Task | Functions |
|---|---|
| Restrict or wrap values | `clamp()`, `clamp01()`, `in_range()`, `wrap()` |
| Transform ranges | `lerp()`, `inv_lerp()`, `remap()`, `midpoint()` |
| Handle division by zero | `divide_or()` |
| Compute or normalize Euclidean length | `l2_norm()`, `normalize_l2()` |
| Preserve-length differences | `adjacent_difference()` |

## Usage

```{r setup}
library(numops)
```

### Bounds and periodic values

Clamp values to a closed interval or wrap them to a half-open periodic
interval:

```{r bounds}
clamp01(c(-1, 0.25, 1.5))
wrap(c(-10, 0, 370), lower = 0, upper = 360)
```

### Interpolation and remapping

Interpolate between endpoints or map values from one interval to another:

```{r interpolation}
lerp(10, 20, c(0, 0.25, 1))
remap(c(0, 50, 100), from = c(0, 100), to = c(-1, 1))
```

Values outside the source interval are extrapolated rather than clamped.

### Division with a fallback

Choose the result returned where a denominator is zero:

```{r division}
divide_or(
c(12, 8, 5),
c(3, 0, 2),
default = NA_real_
)
```

### Vector, matrix, and array norms

Use `margin` to compute or normalize independent slices. For matrices,
`margin = 1` selects rows and `margin = 2` selects columns:

```{r norms}
x <- matrix(
c(3, 4, 0, 1, 2, 2),
nrow = 2,
byrow = TRUE
)

l2_norm(x, margin = 1)
normalize_l2(x, margin = 1)
```

## Recycling and output shape

Functions with multiple numeric inputs use strict scalar recycling. Each input
must have length one or a shared length; other length combinations are errors.
Length-one inputs are recycled to the shared length.

Names, dimensions, and dimnames are copied from the first input already having
the shared length. Functions that transform a single object preserve its shape.

## Getting help

If you find a bug or have a feature request, please open an issue on the
[GitHub issue tracker](https://github.com/Macosso/numops/issues).
114 changes: 114 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@

<!-- README.md is generated from README.Rmd. Please edit that file. -->

# numops

<!-- badges: start -->

[![R-CMD-check](https://github.com/Macosso/numops/actions/workflows/R-CMD-check.yaml/badge.svg)](https://github.com/Macosso/numops/actions/workflows/R-CMD-check.yaml)
<!-- badges: end -->

numops provides small, dependency-free numerical operations for vectors,
matrices, and arrays. It collects common tasks that otherwise require
repeated base R expressions and gives them consistent validation, scalar
recycling, and shape-preserving behavior.

## Installation

You can install the development version of numops from
[GitHub](https://github.com/Macosso/numops) with:

``` r
# install.packages("pak")
pak::pak("Macosso/numops")
```

## Overview

| Task | Functions |
|----|----|
| Restrict or wrap values | `clamp()`, `clamp01()`, `in_range()`, `wrap()` |
| Transform ranges | `lerp()`, `inv_lerp()`, `remap()`, `midpoint()` |
| Handle division by zero | `divide_or()` |
| Compute or normalize Euclidean length | `l2_norm()`, `normalize_l2()` |
| Preserve-length differences | `adjacent_difference()` |

## Usage

``` r
library(numops)
```

### Bounds and periodic values

Clamp values to a closed interval or wrap them to a half-open periodic
interval:

``` r
clamp01(c(-1, 0.25, 1.5))
#> [1] 0.00 0.25 1.00
wrap(c(-10, 0, 370), lower = 0, upper = 360)
#> [1] 350 0 10
```

### Interpolation and remapping

Interpolate between endpoints or map values from one interval to
another:

``` r
lerp(10, 20, c(0, 0.25, 1))
#> [1] 10.0 12.5 20.0
remap(c(0, 50, 100), from = c(0, 100), to = c(-1, 1))
#> [1] -1 0 1
```

Values outside the source interval are extrapolated rather than clamped.

### Division with a fallback

Choose the result returned where a denominator is zero:

``` r
divide_or(
c(12, 8, 5),
c(3, 0, 2),
default = NA_real_
)
#> [1] 4.0 NA 2.5
```

### Vector, matrix, and array norms

Use `margin` to compute or normalize independent slices. For matrices,
`margin = 1` selects rows and `margin = 2` selects columns:

``` r
x <- matrix(
c(3, 4, 0, 1, 2, 2),
nrow = 2,
byrow = TRUE
)

l2_norm(x, margin = 1)
#> [1] 5 3
normalize_l2(x, margin = 1)
#> [,1] [,2] [,3]
#> [1,] 0.6000000 0.8000000 0.0000000
#> [2,] 0.3333333 0.6666667 0.6666667
```

## Recycling and output shape

Functions with multiple numeric inputs use strict scalar recycling. Each
input must have length one or a shared length; other length combinations
are errors. Length-one inputs are recycled to the shared length.

Names, dimensions, and dimnames are copied from the first input already
having the shared length. Functions that transform a single object
preserve its shape.

## Getting help

If you find a bug or have a feature request, please open an issue on the
[GitHub issue tracker](https://github.com/Macosso/numops/issues).