Skip to content

Commit b9396e3

Browse files
feat: add ml/base/loss/float64/hinge-gradient
PR-URL: #12216 Co-authored-by: Athan Reines <kgryte@gmail.com> Reviewed-by: Athan Reines <kgryte@gmail.com> Signed-off-by: Nakul Krishnakumar <nakulkrishnakumar86@gmail.com> Signed-off-by: Athan Reines <kgryte@gmail.com>
1 parent 075cabd commit b9396e3

30 files changed

Lines changed: 2286 additions & 0 deletions

File tree

Lines changed: 244 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,244 @@
1+
<!--
2+
3+
@license Apache-2.0
4+
5+
Copyright (c) 2026 The Stdlib Authors.
6+
7+
Licensed under the Apache License, Version 2.0 (the "License");
8+
you may not use this file except in compliance with the License.
9+
You may obtain a copy of the License at
10+
11+
http://www.apache.org/licenses/LICENSE-2.0
12+
13+
Unless required by applicable law or agreed to in writing, software
14+
distributed under the License is distributed on an "AS IS" BASIS,
15+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16+
See the License for the specific language governing permissions and
17+
limitations under the License.
18+
19+
-->
20+
21+
# hingeGradient
22+
23+
> Compute the [hinge loss gradient][hinge-loss-gradient] with respect to a model parameter.
24+
25+
<section class="intro">
26+
27+
The [hinge loss gradient][hinge-loss-gradient] is defined as
28+
29+
<!-- <equation class="equation" label="eq:hinge_loss_gradient" align="center" raw="\frac{\partial \ell}{\partial w_i} = \begin{cases} -yx_i & \text{if } yp \leq t \\ 0 & \text{otherwise} \end{cases}" alt="Equation for the hinge loss gradient."> -->
30+
31+
```math
32+
\frac{\partial \ell}{\partial w_i} = \begin{cases} -yx_i & \text{if } yp \leq t \\ 0 & \text{otherwise} \end{cases}
33+
```
34+
35+
<!-- </equation> -->
36+
37+
</section>
38+
39+
<!-- /.intro -->
40+
41+
<section class="usage">
42+
43+
## Usage
44+
45+
```javascript
46+
var hingeGradient = require( '@stdlib/ml/base/loss/float64/hinge-gradient' );
47+
```
48+
49+
#### hingeGradient( x, t, y, p )
50+
51+
Computes the [hinge loss gradient][hinge-loss-gradient] with respect to a model parameter.
52+
53+
```javascript
54+
var v = hingeGradient( 3.0, 1.0, 1.0, 0.782 );
55+
// returns -3.0
56+
57+
v = hingeGradient( -1.3, 1.0, 1.0, -0.999 );
58+
// returns 1.3
59+
```
60+
61+
The function accepts the following arguments:
62+
63+
- **x**: input value.
64+
- **t**: margin threshold.
65+
- **y**: true target value.
66+
- **p**: predicted value.
67+
68+
If any argument is `NaN`, the function returns `NaN`.
69+
70+
```javascript
71+
var v = hingeGradient( NaN, 1.0, 1.0, 0.782 );
72+
// returns NaN
73+
74+
v = hingeGradient( 1.0, 1.0, NaN, 0.782 );
75+
// returns NaN
76+
77+
v = hingeGradient( NaN, NaN, 1.0, 0.782 );
78+
// returns NaN
79+
80+
v = hingeGradient( NaN, NaN, NaN, NaN );
81+
// returns NaN
82+
```
83+
84+
If `y` is not +1 or -1, the function returns `NaN`.
85+
86+
```javascript
87+
var v = hingeGradient( 3.0, 1.0, -0.9, 1.0 );
88+
// returns NaN
89+
90+
v = hingeGradient( 2.4, 1.0, 0.453, 0.76 );
91+
// returns NaN
92+
```
93+
94+
</section>
95+
96+
<!-- /.usage -->
97+
98+
<section class="notes">
99+
100+
## Notes
101+
102+
- When `t = 1.0`, we get the loss used by SVM, where as when `t = 0.0`, we get the loss used by the Perceptron.
103+
104+
</section>
105+
106+
<!-- /.notes -->
107+
108+
<section class="examples">
109+
110+
## Examples
111+
112+
<!-- eslint no-undef: "error" -->
113+
114+
```javascript
115+
var uniform = require( '@stdlib/random/array/uniform' );
116+
var sample = require( '@stdlib/random/sample' );
117+
var logEachMap = require( '@stdlib/console/log-each-map' );
118+
var hingeGradient = require( '@stdlib/ml/base/loss/float64/hinge-gradient' );
119+
120+
var y = sample( [ -1.0, 1.0 ], {
121+
'size': 100
122+
});
123+
var opts = {
124+
'dtype': 'float64'
125+
};
126+
var x = uniform( 100, -100.0, 100.0, opts );
127+
var t = uniform( 100, 0.0, 5.0, opts );
128+
var p = uniform( 100, -5.0, 5.0, opts );
129+
130+
logEachMap( 'hingeGradient(%0.4f, %0.4f, %0.4f, %0.4f) = %0.4f', x, t, y, p, hingeGradient );
131+
```
132+
133+
</section>
134+
135+
<!-- /.examples -->
136+
137+
<!-- C interface documentation. -->
138+
139+
* * *
140+
141+
<section class="c">
142+
143+
## C APIs
144+
145+
<!-- Section to include introductory text. Make sure to keep an empty line after the intro `section` element and another before the `/section` close. -->
146+
147+
<section class="intro">
148+
149+
</section>
150+
151+
<!-- /.intro -->
152+
153+
<!-- C usage documentation. -->
154+
155+
<section class="usage">
156+
157+
### Usage
158+
159+
```c
160+
#include "stdlib/ml/base/loss/float64/hinge_gradient.h"
161+
```
162+
163+
#### stdlib_base_float64_hinge_gradient( x, t, y, p )
164+
165+
Computes the [hinge loss gradient][hinge-loss-gradient] with respect to a model parameter.
166+
167+
```c
168+
double out = stdlib_base_float64_hinge_gradient( 3.0, 1.0, 1.0, 0.782 );
169+
// returns -3.0
170+
```
171+
172+
The function accepts the following arguments:
173+
174+
- **x**: `[in] double` input value.
175+
- **t**: `[in] double` margin threshold.
176+
- **y**: `[in] double` true target value.
177+
- **p**: `[in] double` predicted value.
178+
179+
```c
180+
double stdlib_base_float64_hinge_gradient( const double x, const double t, const double y, const double p );
181+
```
182+
183+
</section>
184+
185+
<!-- /.usage -->
186+
187+
<!-- C API usage notes. Make sure to keep an empty line after the `section` element and another before the `/section` close. -->
188+
189+
<section class="notes">
190+
191+
</section>
192+
193+
<!-- /.notes -->
194+
195+
<!-- C API usage examples. -->
196+
197+
<section class="examples">
198+
199+
### Examples
200+
201+
```c
202+
#include "stdlib/ml/base/loss/float64/hinge_gradient.h"
203+
#include <stdio.h>
204+
205+
int main( void ) {
206+
const double x[] = { -10.0, -9.56, -8.67, -7.78, -6.89, 6.89, 7.78, 8.67, 9.56, 10.0 };
207+
const double t[] = { 0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0 };
208+
const double y[] = { -1.0, -1.0, -1.0, -1.0, -1.0, 1.0, 1.0, 1.0, 1.0, 1.0 };
209+
const double p[] = { -5.0, -3.89, -2.78, -1.67, -0.56, 0.56, 1.67, 2.78, 3.89, 5.0 };
210+
211+
double v;
212+
int i;
213+
for ( i = 0; i < 10; i++ ) {
214+
v = stdlib_base_float64_hinge_gradient( x[ i ], t[ i ], y[ i ], p[ i ] );
215+
printf( "hingeGradient(%lf, %lf, %lf, %lf) = %lf\n", x[ i ], t[ i ], y[ i ], p[ i ], v );
216+
}
217+
}
218+
```
219+
220+
</section>
221+
222+
<!-- /.examples -->
223+
224+
</section>
225+
226+
<!-- /.c -->
227+
228+
<!-- Section for related `stdlib` packages. Do not manually edit this section, as it is automatically populated. -->
229+
230+
<section class="related">
231+
232+
</section>
233+
234+
<!-- /.related -->
235+
236+
<!-- Section for all links. Make sure to keep an empty line after the `section` element and another before the `/section` close. -->
237+
238+
<section class="links">
239+
240+
[hinge-loss-gradient]: https://en.wikipedia.org/wiki/Hinge_loss#Optimization
241+
242+
</section>
243+
244+
<!-- /.links -->
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
/**
2+
* @license Apache-2.0
3+
*
4+
* Copyright (c) 2026 The Stdlib Authors.
5+
*
6+
* Licensed under the Apache License, Version 2.0 (the "License");
7+
* you may not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing, software
13+
* distributed under the License is distributed on an "AS IS" BASIS,
14+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
* See the License for the specific language governing permissions and
16+
* limitations under the License.
17+
*/
18+
19+
'use strict';
20+
21+
// MODULES //
22+
23+
var bench = require( '@stdlib/bench' );
24+
var uniform = require( '@stdlib/random/array/uniform' );
25+
var sample = require( '@stdlib/random/sample' );
26+
var isnan = require( '@stdlib/math/base/assert/is-nan' );
27+
var pkg = require( './../package.json' ).name;
28+
var hingeGradient = require( './../lib' );
29+
30+
31+
// MAIN //
32+
33+
bench( pkg, function benchmark( b ) {
34+
var len;
35+
var x;
36+
var y;
37+
var p;
38+
var v;
39+
var i;
40+
41+
len = 100;
42+
y = sample( [ -1.0, 1.0 ], {
43+
'size': len
44+
});
45+
x = uniform( len, -100.0, 100.0 );
46+
p = uniform( len, -2.0, 2.0 );
47+
48+
b.tic();
49+
for ( i = 0; i < b.iterations; i++ ) {
50+
v = hingeGradient( x[ i%x.length ], 1.0, y[ i%y.length ], p[ i%p.length ] );
51+
if ( isnan( v ) ) {
52+
b.fail( 'should not return NaN' );
53+
}
54+
}
55+
b.toc();
56+
if ( isnan( v ) ) {
57+
b.fail( 'should not return NaN' );
58+
}
59+
b.pass( 'benchmark finished' );
60+
b.end();
61+
});
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
/**
2+
* @license Apache-2.0
3+
*
4+
* Copyright (c) 2026 The Stdlib Authors.
5+
*
6+
* Licensed under the Apache License, Version 2.0 (the "License");
7+
* you may not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing, software
13+
* distributed under the License is distributed on an "AS IS" BASIS,
14+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
* See the License for the specific language governing permissions and
16+
* limitations under the License.
17+
*/
18+
19+
'use strict';
20+
21+
// MODULES //
22+
23+
var resolve = require( 'path' ).resolve;
24+
var bench = require( '@stdlib/bench' );
25+
var uniform = require( '@stdlib/random/array/uniform' );
26+
var sample = require( '@stdlib/random/sample' );
27+
var isnan = require( '@stdlib/math/base/assert/is-nan' );
28+
var tryRequire = require( '@stdlib/utils/try-require' );
29+
var format = require( '@stdlib/string/format' );
30+
var pkg = require( './../package.json' ).name;
31+
32+
33+
// VARIABLES //
34+
35+
var hingeGradient = tryRequire( resolve( __dirname, './../lib/native.js' ) );
36+
var opts = {
37+
'skip': ( hingeGradient instanceof Error )
38+
};
39+
40+
41+
// MAIN //
42+
43+
bench( format( '%s::native', pkg ), opts, function benchmark( b ) {
44+
var len;
45+
var x;
46+
var y;
47+
var p;
48+
var v;
49+
var i;
50+
51+
len = 100;
52+
y = sample( [ -1.0, 1.0 ], {
53+
'size': len
54+
});
55+
x = uniform( len, -100.0, 100.0 );
56+
p = uniform( len, -2.0, 2.0 );
57+
58+
b.tic();
59+
for ( i = 0; i < b.iterations; i++ ) {
60+
v = hingeGradient( x[ i%x.length ], 1.0, y[ i%y.length ], p[ i%p.length ] );
61+
if ( isnan( v ) ) {
62+
b.fail( 'should not return NaN' );
63+
}
64+
}
65+
b.toc();
66+
if ( isnan( v ) ) {
67+
b.fail( 'should not return NaN' );
68+
}
69+
b.pass( 'benchmark finished' );
70+
b.end();
71+
});

0 commit comments

Comments
 (0)