Skip to content

Commit 67dc6b2

Browse files
Merge pull request #8 from RubixML/4.1
4.1
2 parents a45bbe2 + c19493e commit 67dc6b2

45 files changed

Lines changed: 1780 additions & 250 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎CHANGELOG.md‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
# Change Log
22

3+
- 4.1.0
4+
- Added `softplus()` and `erf()` special functions
5+
- Added `sinh()` and `cosh()` trigonometric functions
6+
- Added reciprocal square root `rsqrt()` function
7+
38
- 4.0.1
49
- Optimize Vector `range()` and `linspace()` factories
510

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
<?php
2+
3+
namespace Tensor\Benchmarks\Unary;
4+
5+
use Tensor\Matrix;
6+
use Generator;
7+
8+
/**
9+
* Softplus as a fused kernel, against the exp/add/log composition it replaces.
10+
*
11+
* @Groups({"Functions"})
12+
* @BeforeMethods({"setUp"})
13+
*/
14+
class SoftplusMatrixBench
15+
{
16+
/**
17+
* @var Matrix
18+
*/
19+
protected $a;
20+
21+
/**
22+
* @param array $params
23+
*/
24+
public function setUp(array $params) : void
25+
{
26+
$this->a = Matrix::uniform(...$params['size']);
27+
}
28+
29+
/**
30+
* @return list<array{size: list<int>}>
31+
*/
32+
public function sizes() : Generator
33+
{
34+
yield 'small' => ['size' => [1024, 1024]];
35+
yield 'medium' => ['size' => [4096, 4096]];
36+
yield 'large' => ['size' => [8192, 8192]];
37+
}
38+
39+
/**
40+
* @Subject
41+
* @Iterations(5)
42+
* @ParamProviders({"sizes"})
43+
* @OutputTimeUnit("milliseconds", precision=3)
44+
*/
45+
public function benchFused() : void
46+
{
47+
$this->a->softplus();
48+
}
49+
50+
/**
51+
* @Subject
52+
* @Iterations(5)
53+
* @ParamProviders({"sizes"})
54+
* @OutputTimeUnit("milliseconds", precision=3)
55+
*/
56+
public function benchComposed() : void
57+
{
58+
$e = $this->a->exp();
59+
60+
$e->add(1.0)->log();
61+
}
62+
}

‎config.json‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
"extension-name": "tensor",
55
"description": "Scientific computing for the PHP language.",
66
"author": "The Rubix ML Community",
7-
"version": "4.0.1",
7+
"version": "4.1.0",
88
"verbose": true,
99
"extra-cflags": "-O3 -fno-math-errno",
1010
"extra-libs": "-lopenblas -llapacke -lgfortran",

‎docs/Matrix.md‎

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -419,12 +419,12 @@ See [Unary](interfaces/unary.md). Each method returns a new `Matrix`.
419419
- `abs() : self` — absolute value of each element
420420
- `square() : self` — square of the matrix element-wise
421421
- `sqrt() : self` — square root of the matrix
422+
- `rsqrt() : self` — reciprocal square root of the matrix
422423
- `reciprocal() : self` — element-wise reciprocal of the matrix
423424
- `exp() : self` — exponential of the matrix
424425
- `expm1() : self` — exponential of each element minus 1
425426
- `log(float $base = M_E) : self` — logarithm of the matrix in the specified base
426427
- `log1p() : self` — log of 1 plus each element
427-
- `sigmoid() : self` — element-wise logistic function, `1 / (1 + exp(-x))`
428428
- `round(int $precision = 0) : self` — round the elements to a given decimal place (throws `InvalidArgumentException` if `$precision < 0`)
429429
- `floor() : self` — round down to the nearest integer
430430
- `ceil() : self` — round up to the nearest integer
@@ -445,6 +445,8 @@ See [Trigonometric](interfaces/trigonometric.md). Each method returns a new `Mat
445445
- `tan()` — tangent of the matrix
446446
- `atan()` — arc tangent of the matrix
447447
- `tanh() : self` — element-wise hyperbolic tangent
448+
- `sinh() : self` — element-wise hyperbolic sine
449+
- `cosh() : self` — element-wise hyperbolic cosine
448450
- `rad2deg()` — convert angles from radians to degrees
449451
- `deg2rad()` — convert angles from degrees to radians
450452

@@ -466,9 +468,12 @@ See [Reductions](interfaces/reductions.md). For a `Matrix`, row-wise reductions
466468

467469
## Special
468470

469-
See [Special](interfaces/special.md). These preserve the shape of the matrix without being element-wise.
471+
See [Special](interfaces/special.md). `softmax()` preserves the shape of the matrix; `erf()` is element-wise.
470472

473+
- `sigmoid() : self` — element-wise logistic function, `1 / (1 + exp(-x))`
474+
- `softplus() : self` — element-wise softplus, `log(1 + exp(x))`
471475
- `softmax() : self` — exponentials normalized so each **row** sums to `1.0`; transpose on either side to normalize each column
476+
- `erf() : self` — element-wise Gaussian error function
472477

473478
## Array Access
474479

‎docs/Vector.md‎

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -302,12 +302,14 @@ See [Unary](interfaces/unary.md). Each method returns a new `Vector`.
302302
- `abs() : self` — absolute value of the vector
303303
- `square() : self` — square the vector
304304
- `sqrt() : self` — square root of the vector
305+
- `rsqrt() : self` — reciprocal square root of the vector
305306
- `reciprocal() : self` — element-wise reciprocal of the vector
306307
- `exp() : self` — exponentiate each element
307308
- `expm1() : self` — exponential of each element minus 1
308309
- `log(float $base = M_E) : self` — log to the given base of each element
309310
- `log1p() : self` — log of 1 plus each element
310311
- `sigmoid() : self` — element-wise logistic function, `1 / (1 + exp(-x))`
312+
- `softplus() : self` — element-wise softplus, `log(1 + exp(x))`
311313
- `round(int $precision = 0) : self` — round the elements to a given decimal place (throws `InvalidArgumentException` if `$precision < 0`)
312314
- `floor() : self` — round down to the nearest integer
313315
- `ceil() : self` — round up to the nearest integer
@@ -328,6 +330,8 @@ See [Trigonometric](interfaces/trigonometric.md). Each method returns a new `Vec
328330
- `tan()` — tangent of the vector
329331
- `atan()` — arc tangent of the vector
330332
- `tanh() : self` — element-wise hyperbolic tangent
333+
- `sinh() : self` — element-wise hyperbolic sine
334+
- `cosh() : self` — element-wise hyperbolic cosine
331335
- `rad2deg()` — convert angles from radians to degrees
332336
- `deg2rad()` — convert angles from degrees to radians
333337

@@ -348,9 +352,10 @@ See [Reductions](interfaces/reductions.md). For a `Vector` these return scalar `
348352

349353
## Special
350354

351-
See [Special](interfaces/special.md). These preserve the shape of the vector without being element-wise.
355+
See [Special](interfaces/special.md). `softmax()` preserves the shape of the vector; `erf()` is element-wise.
352356

353357
- `softmax() : self` — the exponentials of the vector normalized so they sum to `1.0`
358+
- `erf() : self` — element-wise Gaussian error function
354359

355360
## Array Access
356361

‎docs/index.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ Tensor \
5555
| [Unary](interfaces/unary.md) | Element-wise unary functions, including clipping. |
5656
| [Trigonometric](interfaces/trigonometric.md) | Element-wise trigonometric functions. |
5757
| [Reductions](interfaces/reductions.md) | Aggregate reduction operations, including the statistical summaries. |
58-
| [Special](interfaces/special.md) | Operations that preserve shape without being element-wise, such as `softmax`. |
58+
| [Special](interfaces/special.md) | Operations that fit no other group, such as `softmax` and the error-function `erf`. |
5959

6060
## Decompositions
6161

‎docs/interfaces/special.md‎

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,31 @@ Operations that do not belong to any of the other interface groups.
66

77
## Overview
88

9-
`Special` holds the operations that neither pointwise element-wise functions (`Arithmetic`, `Comparable`, `Unary`, `Trigonometric`), nor aggregate reductions (`Reductions`), nor array-like access (`ArrayLike`) can describe.
9+
`Special` holds the operations that neither the basic algebraic and trigonometric families (`Arithmetic`, `Comparable`, `Unary`, `Trigonometric`), aggregate reductions (`Reductions`), nor array-like access (`ArrayLike`) can describe.
1010

11-
`softmax()` is the sole member: it preserves the shape of the tensor, but each element of the output depends on a whole reduction axis rather than on one input element, so it is neither element-wise nor a reduction.
11+
`softmax()` is the only shape-preserving member whose output depends on a whole reduction axis rather than on one input element, so it is neither element-wise nor a reduction. `erf()` is an element-wise error-function transform grouped here so the error-function family stays together, distinct from the basic algebraic operations.
1212

1313
```php
1414
interface Special
1515
```
1616

1717
## Methods
1818

19+
### `sigmoid() : mixed`
20+
21+
Return the element-wise logistic function, `1 / (1 + exp(-x))`.
22+
23+
A large negative input saturates to exactly `0.0` and a large positive one to
24+
exactly `1.0`, so the result never overflows to an infinity.
25+
26+
### `softplus() : mixed`
27+
28+
Return the element-wise softplus, `log(1 + exp(x))`.
29+
30+
The computation is numerically stable: for a large positive input it reduces to
31+
`x + log1p(0) == x` and for a large negative input to `log1p(0) == 0.0`, so the
32+
result never overflows to an infinity.
33+
1934
### `softmax() : mixed`
2035

2136
Return the softmax of the tensor, i.e. the exponentials of its elements
@@ -36,3 +51,10 @@ The maximum of each row is subtracted before exponentiating, so no intermediate
3651
can overflow regardless of the magnitude of the input, and a single-element row
3752
normalizes to `1.0`. Note the degenerate case this implies: a matrix with a
3853
single *column* has one-element rows, so it normalizes to all ones.
54+
55+
### `erf() : mixed`
56+
57+
Return the element-wise Gaussian error function.
58+
59+
A large input saturates to exactly `1.0` or `-1.0` rather than returning an
60+
infinity.

‎docs/interfaces/tensor.md‎

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,16 +20,15 @@ interface Tensor extends ArrayLike, Arithmetic, Comparable,
2020
| [ArrayLike](arraylike.md) | `shape`, `shapeString`, `size`, `map`, `reduce`, `asArray` |
2121
| [Arithmetic](arithmetic.md) | `multiply`, `divide`, `add`, `subtract`, `pow`, `mod` |
2222
| [Comparable](comparable.md) | `equal`, `notEqual`, `greater`, `greaterEqual`, `less`, `lessEqual` |
23-
| [Unary](unary.md) | `abs`, `square`, `sqrt`, `exp`, `expm1`, `log`, `log1p`, `sigmoid`, `round`, `floor`, `ceil`, `sign`, `negate`, `clip`, `clipLower`, `clipUpper` |
24-
| [Trigonometric](trigonometric.md) | `sin`, `asin`, `cos`, `acos`, `tan`, `atan`, `tanh`, `rad2deg`, `deg2rad` |
23+
| [Unary](unary.md) | `abs`, `square`, `sqrt`, `rsqrt`, `exp`, `expm1`, `log`, `log1p`, `round`, `floor`, `ceil`, `sign`, `negate`, `clip`, `clipLower`, `clipUpper` |
24+
| [Trigonometric](trigonometric.md) | `sin`, `asin`, `cos`, `acos`, `tan`, `atan`, `tanh`, `sinh`, `cosh`, `rad2deg`, `deg2rad` |
2525
| [Reductions](reductions.md) | `sum`, `product`, `min`, `max`, `argmin`, `argmax`, `mean`, `variance`, `median`, `quantile` |
26-
| [Special](special.md) | `softmax` |
26+
| [Special](special.md) | `sigmoid`, `softplus`, `softmax`, `erf` |
2727

2828
Every group is homogeneous in what it does to the tensor's shape: `Arithmetic`,
2929
`Comparable`, `Unary`, and `Trigonometric` are element-wise and preserve it,
3030
`Reductions` collapse it, and `ArrayLike` is about access rather than arithmetic.
31-
`Special` is the escape hatch for operations that preserve the shape without being
32-
element-wise.
31+
`Special` is the escape hatch for operations that fit no other group, such as shape-preserving cross-axis operations like `softmax()` and the element-wise error-function family `erf()`.
3332

3433
Additionally, because `ArrayLike` extends `ArrayAccess`, `IteratorAggregate`, and `Countable`, every tensor is array-accessible, iterable, and countable.
3534

‎docs/interfaces/trigonometric.md‎

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,3 +52,15 @@ Return the element-wise hyperbolic tangent.
5252

5353
A large input saturates to exactly `1.0` or `-1.0` rather than returning an
5454
infinity.
55+
56+
### `sinh() : mixed`
57+
58+
Return the element-wise hyperbolic sine.
59+
60+
### `cosh() : mixed`
61+
62+
Return the element-wise hyperbolic cosine.
63+
64+
The result is always positive, and `cosh(0) == 1.0`. For a large input it grows
65+
as `exp(|x|) / 2`, so it can overflow to an infinity for sufficiently large
66+
arguments.

‎docs/interfaces/unary.md‎

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,10 @@ Square the tensor.
2626

2727
Return the square root of the tensor.
2828

29+
### `rsqrt() : mixed`
30+
31+
Return the reciprocal square root of the tensor.
32+
2933
### `reciprocal() : mixed`
3034

3135
Return the element-wise reciprocal of the tensor.
@@ -49,13 +53,6 @@ Return the logarithm of the tensor in a specified base.
4953

5054
Return the log of 1 plus the tensor, i.e. a transform.
5155

52-
### `sigmoid() : mixed`
53-
54-
Return the element-wise logistic function, `1 / (1 + exp(-x))`.
55-
56-
A large negative input saturates to exactly `0.0` and a large positive one to
57-
exactly `1.0`, so the result never overflows to an infinity.
58-
5956
### `round(int $precision = 0) : self`
6057

6158
Round the elements in the tensor to a given decimal place.

0 commit comments

Comments
 (0)